初始提交
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
import time
|
||||
|
||||
import pytest
|
||||
from playwright.async_api import async_playwright
|
||||
|
||||
from common.base_page_test import BasePageTest
|
||||
from common.config import Config
|
||||
|
||||
|
||||
class ConfigManagementTest(BasePageTest):
|
||||
"""参数设置测试类"""
|
||||
|
||||
def generate_config_data(self) -> dict:
|
||||
"""生成测试数据"""
|
||||
timestamp = int(time.time())
|
||||
return {
|
||||
'config_name': f'test_config_{timestamp}',
|
||||
'config_key': f'test_config_key_{timestamp}',
|
||||
'config_value': f'test_config_value_{timestamp}',
|
||||
}
|
||||
|
||||
async def create_config(self, config_name: str, config_key: str, config_value: str) -> None:
|
||||
"""创建参数配置"""
|
||||
# 点击新增按钮
|
||||
await self.page.get_by_role('button', name='新增').first.click()
|
||||
|
||||
# 等待对话框
|
||||
dialog = self.page.get_by_role('dialog')
|
||||
await dialog.wait_for()
|
||||
|
||||
# 填写参数信息
|
||||
await dialog.get_by_role('textbox', name='参数名称').fill(config_name)
|
||||
await dialog.get_by_role('textbox', name='参数键名').fill(config_key)
|
||||
await dialog.get_by_role('textbox', name='参数键值').fill(config_value)
|
||||
|
||||
# 等待一段时间确保输入完成
|
||||
await self.page.wait_for_timeout(500)
|
||||
|
||||
# 选择参数状态 - 选择系统内置选项为N(否),避免后端限制删除
|
||||
# 在对话框中找到系统内置的单选按钮并选择
|
||||
await self.wait_for_selector('input[type="radio"]', timeout=5000)
|
||||
# 点击系统内置'否'选项
|
||||
# 根据codegen脚本,使用更精确的定位器
|
||||
await self.page.locator('label:nth-child(2) > .el-radio__input > .el-radio__inner').click()
|
||||
|
||||
# 等待一段时间确保选择完成
|
||||
await self.page.wait_for_timeout(500)
|
||||
|
||||
# 点击确认按钮
|
||||
confirm_button = self.page.get_by_role('button', name='确 定').first
|
||||
await confirm_button.click()
|
||||
|
||||
# 等待一段时间确保请求发送
|
||||
await self.page.wait_for_timeout(1000)
|
||||
|
||||
# 等待新增成功提示
|
||||
await self.wait_for_selector('div:has-text("新增成功")', timeout=10000)
|
||||
|
||||
async def search_config(self, config_name: str, config_key: str = '') -> None:
|
||||
"""搜索参数配置"""
|
||||
# 在查询表单中输入参数信息进行查询
|
||||
await self.page.get_by_role('textbox', name='参数名称').fill(config_name)
|
||||
if config_key:
|
||||
await self.page.get_by_role('textbox', name='参数键名').fill(config_key)
|
||||
|
||||
# 点击搜索按钮
|
||||
await self.page.get_by_role('button', name='搜索').first.click()
|
||||
|
||||
# 等待搜索结果加载
|
||||
await self.page.wait_for_timeout(1000)
|
||||
|
||||
async def edit_config(self, updated_value: str) -> None:
|
||||
"""编辑参数配置"""
|
||||
# 点击编辑按钮
|
||||
await self.page.locator('tbody').get_by_role('button', name='修改').nth(0).click()
|
||||
|
||||
# 等待对话框
|
||||
dialog = self.page.get_by_role('dialog')
|
||||
await dialog.wait_for()
|
||||
|
||||
# 修改参数键值
|
||||
await dialog.get_by_role('textbox', name='参数键值').fill(updated_value)
|
||||
|
||||
# 确认
|
||||
await self.page.get_by_role('button', name='确 定').first.click()
|
||||
|
||||
# 等待编辑成功提示
|
||||
await self.wait_for_selector('div:has-text("修改成功")', timeout=10000)
|
||||
|
||||
async def delete_config(self) -> None:
|
||||
"""删除参数配置"""
|
||||
# 点击删除按钮
|
||||
await self.page.locator('tbody').get_by_role('button', name='删除').nth(0).click()
|
||||
|
||||
# 确认删除
|
||||
await self.page.get_by_role('button', name='确定').first.click()
|
||||
|
||||
# 等待删除成功提示
|
||||
await self.wait_for_selector('div:has-text("删除成功")', timeout=10000)
|
||||
|
||||
# 重置查询表单,确保能看到所有参数
|
||||
reset_button = self.page.get_by_role('button', name='重置')
|
||||
await reset_button.click()
|
||||
|
||||
# 等待列表刷新
|
||||
await self.page.wait_for_timeout(1000)
|
||||
|
||||
async def test_config_crud_operations(self) -> None:
|
||||
"""测试参数设置的增删查改功能"""
|
||||
# 访问参数设置页面
|
||||
await self.goto_page(Config.frontend_url + '/system/config')
|
||||
|
||||
# 等待页面加载完成
|
||||
await self.wait_for_page_title('参数设置', timeout=10000)
|
||||
await self.page.wait_for_timeout(1000) # 等待列表刷新
|
||||
|
||||
# 记录初始参数数量
|
||||
initial_config_count = await self.get_table_total_rows()
|
||||
|
||||
# 生成测试数据
|
||||
data = self.generate_config_data()
|
||||
|
||||
# 1.新增
|
||||
await self.create_config(data['config_name'], data['config_key'], data['config_value'])
|
||||
|
||||
# 验证新增
|
||||
await self.page.wait_for_timeout(1000) # 等待列表刷新
|
||||
new_config_count = await self.get_table_total_rows()
|
||||
assert new_config_count > initial_config_count, '新增参数后数量应该增加'
|
||||
|
||||
# 2.搜索
|
||||
await self.search_config(data['config_name'], data['config_key'])
|
||||
|
||||
# 验证搜索
|
||||
search_result_count = await self.get_table_total_rows()
|
||||
assert search_result_count >= 1, '搜索结果应该至少包含一个参数'
|
||||
|
||||
# 3.编辑
|
||||
await self.edit_config(f'updated_config_value_{time.time()}')
|
||||
|
||||
# 验证编辑
|
||||
await self.page.wait_for_timeout(1000) # 等待列表刷新
|
||||
|
||||
# 重新搜索以验证修改结果
|
||||
await self.search_config(data['config_name'])
|
||||
|
||||
# 4.删除
|
||||
await self.delete_config()
|
||||
|
||||
# 验证删除
|
||||
await self.page.wait_for_timeout(1000) # 等待列表刷新
|
||||
final_config_count = await self.get_table_total_rows()
|
||||
assert final_config_count == initial_config_count, '删除参数后数量应该恢复到初始值'
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_config_management_page() -> None:
|
||||
"""测试参数设置页面功能"""
|
||||
async with async_playwright() as p:
|
||||
test_instance = ConfigManagementTest()
|
||||
await test_instance.setup(p)
|
||||
try:
|
||||
await test_instance.test_config_crud_operations()
|
||||
finally:
|
||||
await test_instance.teardown()
|
||||
@@ -0,0 +1,135 @@
|
||||
import time
|
||||
|
||||
import pytest
|
||||
from playwright.async_api import async_playwright
|
||||
|
||||
from common.base_page_test import BasePageTest
|
||||
from common.config import Config
|
||||
|
||||
|
||||
class DeptManagementTest(BasePageTest):
|
||||
"""部门管理页面测试类"""
|
||||
|
||||
def generate_dept_data(self) -> dict:
|
||||
"""生成测试数据"""
|
||||
timestamp = int(time.time())
|
||||
return {
|
||||
'dept_name': f'测试部门_{timestamp}',
|
||||
'order_num': '3',
|
||||
'leader_name': '年糕',
|
||||
}
|
||||
|
||||
async def create_dept(self, dept_name: str, order_num: str) -> None:
|
||||
"""创建部门"""
|
||||
# 点击新增按钮
|
||||
await self.page.get_by_role('button', name='新增').first.click()
|
||||
|
||||
# 等待对话框
|
||||
dialog = self.page.get_by_role('dialog')
|
||||
await dialog.wait_for()
|
||||
|
||||
# 上级部门
|
||||
# 使用 label 定位父级 form-item,再点击内部的 wrapper
|
||||
await dialog.locator('div.el-form-item').filter(has_text='上级部门').locator('.el-select__wrapper').click()
|
||||
# 选择 "集团总公司" (根节点)
|
||||
# 使用 .el-popper 定位下拉框中的内容
|
||||
await self.page.locator('.el-popper:visible').get_by_text('集团总公司').click()
|
||||
|
||||
# 填写部门名称
|
||||
await dialog.get_by_role('textbox', name='部门名称').fill(dept_name)
|
||||
|
||||
# 填写显示排序
|
||||
# el-input-number 通常是一个 spinbutton 或者 input
|
||||
await dialog.get_by_role('spinbutton', name='显示排序').fill(order_num)
|
||||
|
||||
# 点击确定
|
||||
await self.page.get_by_role('button', name='确 定').click()
|
||||
# 等待成功消息
|
||||
await self.wait_for_selector("div:has-text('成功')", timeout=10000)
|
||||
|
||||
async def search_dept(self, dept_name: str) -> None:
|
||||
"""搜索部门"""
|
||||
search_form = self.page.locator('form').first
|
||||
await search_form.get_by_role('textbox', name='部门名称').fill(dept_name)
|
||||
# 点击搜索按钮
|
||||
await self.page.get_by_role('button', name='搜索').first.click()
|
||||
|
||||
# 等待加载
|
||||
await self.page.wait_for_timeout(1000)
|
||||
|
||||
async def edit_dept(self, leader_name: str) -> None:
|
||||
"""编辑部门"""
|
||||
# 点击修改按钮 (第一行)
|
||||
# 树形表格结构可能不同,但通常也是在 tbody 的 row 中
|
||||
await self.page.locator('tbody').get_by_role('button', name='修改').nth(0).click()
|
||||
|
||||
dialog = self.page.get_by_role('dialog')
|
||||
await dialog.wait_for()
|
||||
|
||||
# 修改负责人
|
||||
await dialog.get_by_role('textbox', name='负责人').fill(leader_name)
|
||||
|
||||
# 确定
|
||||
await self.page.get_by_role('button', name='确 定').click()
|
||||
|
||||
# 等待成功提示
|
||||
await self.wait_for_selector('div:has-text("修改成功")', timeout=10000)
|
||||
|
||||
async def delete_dept(self) -> None:
|
||||
"""删除部门"""
|
||||
# 点击删除按钮
|
||||
await self.page.locator('tbody').get_by_role('button', name='删除').nth(0).click()
|
||||
|
||||
# 确认删除
|
||||
await self.page.get_by_role('button', name='确定').click()
|
||||
|
||||
# 等待成功提示
|
||||
await self.wait_for_selector('div:has-text("删除成功")', timeout=10000)
|
||||
|
||||
# 重置搜索
|
||||
await self.page.get_by_role('button', name='重置').click()
|
||||
await self.page.wait_for_timeout(1000)
|
||||
|
||||
async def test_dept_crud_operations(self) -> None:
|
||||
"""测试部门管理增删查改"""
|
||||
# 访问页面
|
||||
await self.goto_page(Config.frontend_url + '/system/dept')
|
||||
await self.wait_for_page_title('部门管理', timeout=10000)
|
||||
|
||||
# 生成测试数据
|
||||
data = self.generate_dept_data()
|
||||
|
||||
# 1. 新增
|
||||
await self.create_dept(data['dept_name'], data['order_num'])
|
||||
|
||||
# 验证新增
|
||||
await self.search_dept(data['dept_name'])
|
||||
# 树形表格,只要有行显示即可
|
||||
rows = await self.page.query_selector_all('.el-table__row')
|
||||
assert len(rows) >= 1, '新增后搜索应有结果'
|
||||
|
||||
# 2. 编辑
|
||||
await self.edit_dept(data['leader_name'])
|
||||
|
||||
# 重新搜索以验证修改结果
|
||||
await self.search_dept(data['dept_name'])
|
||||
|
||||
# 3. 删除
|
||||
await self.delete_dept()
|
||||
|
||||
# 验证删除
|
||||
await self.search_dept(data['dept_name'])
|
||||
rows_after = await self.page.query_selector_all('.el-table__row')
|
||||
assert len(rows_after) == 0, '删除后搜索应无结果'
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_dept_management_page() -> None:
|
||||
"""测试部门管理页面功能"""
|
||||
async with async_playwright() as p:
|
||||
test_instance = DeptManagementTest()
|
||||
await test_instance.setup(p)
|
||||
try:
|
||||
await test_instance.test_dept_crud_operations()
|
||||
finally:
|
||||
await test_instance.teardown()
|
||||
@@ -0,0 +1,201 @@
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
from playwright.async_api import async_playwright
|
||||
|
||||
from common.base_page_test import BasePageTest
|
||||
from common.config import Config
|
||||
|
||||
|
||||
class DictManagementTest(BasePageTest):
|
||||
"""字典管理测试类"""
|
||||
|
||||
def generate_dict_data(self) -> dict:
|
||||
"""生成测试数据"""
|
||||
timestamp = datetime.now().strftime('%H%M%S')
|
||||
return {
|
||||
'dict_name': f'测试字典_{timestamp}',
|
||||
'dict_type': f'test_dict_{timestamp}',
|
||||
'dict_data_label_1': '正常',
|
||||
'dict_data_value_1': '1',
|
||||
'dict_data_label_2': '异常',
|
||||
'dict_data_value_2': '2',
|
||||
'remark': f'备注_{timestamp}',
|
||||
}
|
||||
|
||||
async def create_dict_type(self, dict_name: str, dict_type: str) -> None:
|
||||
"""创建字典类型"""
|
||||
# 点击新增按钮
|
||||
await self.page.get_by_role('button', name='新增').first.click()
|
||||
|
||||
# 等待对话框
|
||||
dialog = self.page.get_by_role('dialog')
|
||||
await dialog.wait_for()
|
||||
|
||||
# 填写表单
|
||||
await dialog.get_by_role('textbox', name='字典名称').fill(dict_name)
|
||||
await dialog.get_by_role('textbox', name='字典类型').fill(dict_type)
|
||||
|
||||
# 提交
|
||||
await dialog.get_by_role('button', name='确 定').click()
|
||||
|
||||
# 验证成功
|
||||
await self.wait_for_selector("div:has-text('新增成功')", timeout=10000)
|
||||
|
||||
async def search_dict_type(self, dict_name: str, dict_type: str) -> None:
|
||||
"""搜索字典类型"""
|
||||
form = self.page.locator('form').first
|
||||
await form.get_by_role('textbox', name='字典名称').fill(dict_name)
|
||||
await form.get_by_role('textbox', name='字典类型').fill(dict_type)
|
||||
# 点击搜索按钮
|
||||
await self.page.get_by_role('button', name='搜索').click()
|
||||
await self.page.wait_for_timeout(1000)
|
||||
|
||||
async def edit_dict_type(self, dict_name: str, remark: str) -> None:
|
||||
"""修改字典类型"""
|
||||
await self.search_dict_type(dict_name, '')
|
||||
|
||||
# 点击修改按钮
|
||||
row = self.page.locator('tbody tr').first
|
||||
await row.get_by_role('button', name='修改').click()
|
||||
|
||||
dialog = self.page.get_by_role('dialog')
|
||||
await dialog.wait_for()
|
||||
|
||||
await dialog.get_by_role('textbox', name='备注').fill(remark)
|
||||
await dialog.get_by_role('button', name='确 定').click()
|
||||
|
||||
await self.wait_for_selector("div:has-text('修改成功')", timeout=10000)
|
||||
|
||||
async def manage_dict_data(self, dict_type: str, data: dict) -> None:
|
||||
"""管理字典数据"""
|
||||
# 1. 进入字典数据页面
|
||||
# 点击字典类型链接
|
||||
row = self.page.locator('tbody tr').first
|
||||
await row.get_by_role('link', name=dict_type).click()
|
||||
|
||||
# 等待页面切换(Playwright在SPA中通常不需要处理多标签页,除非新开tab)
|
||||
# 这里是 router-link,应该是页内跳转
|
||||
# 检查是否到了字典数据页面
|
||||
# 或者等待URL变化,或者等待特定元素
|
||||
# data.vue 有 "关闭" 按钮
|
||||
await self.wait_for_selector("button:has-text('关闭')", timeout=5000)
|
||||
|
||||
# 2. 新增数据1 (正常)
|
||||
await self.create_dict_data(data['dict_data_label_1'], data['dict_data_value_1'], '1', '主要(primary)')
|
||||
|
||||
# 3. 新增数据2 (异常)
|
||||
await self.create_dict_data(data['dict_data_label_2'], data['dict_data_value_2'], '2', '危险(danger)')
|
||||
|
||||
# 4. 修改数据
|
||||
await self.edit_dict_data(data['dict_data_label_2'], '测试备注')
|
||||
|
||||
# 5. 删除数据
|
||||
await self.delete_dict_data(data['dict_data_label_2'])
|
||||
await self.delete_dict_data(data['dict_data_label_1'])
|
||||
|
||||
# 6. 关闭页面 (返回字典类型)
|
||||
await self.page.get_by_role('button', name='关闭', exact=True).click()
|
||||
# 等待返回
|
||||
await self.wait_for_selector('text=字典名称') # 假设返回后能看到原来的页面元素
|
||||
|
||||
async def create_dict_data(self, label: str, value: str, sort: str, list_class: str) -> None:
|
||||
"""创建字典数据"""
|
||||
# 点击新增按钮
|
||||
await self.page.get_by_role('button', name='新增').first.click()
|
||||
|
||||
dialog = self.page.get_by_role('dialog')
|
||||
await dialog.wait_for()
|
||||
|
||||
await dialog.get_by_role('textbox', name='数据标签').fill(label)
|
||||
await dialog.get_by_role('textbox', name='数据键值').fill(value)
|
||||
await dialog.get_by_role('spinbutton', name='显示排序').fill(sort)
|
||||
|
||||
# 选择回显样式
|
||||
# 点击下拉框触发器
|
||||
# el-select 的结构通常是 wrapper -> input (readonly)
|
||||
# 我们可以点击 label 为 "回显样式" 的 form-item 下的 select
|
||||
select_trigger = dialog.locator("label:has-text('回显样式') + div .el-select")
|
||||
if await select_trigger.count() == 0:
|
||||
# 尝试直接找 .el-select,可能布局不同
|
||||
select_trigger = dialog.locator('.el-select').filter(has_text='默认(default)').first
|
||||
|
||||
# 如果还是找不到,尝试点击那个默认值文本
|
||||
if await select_trigger.count() == 0:
|
||||
await dialog.get_by_text('默认(default)').click()
|
||||
else:
|
||||
await select_trigger.click()
|
||||
|
||||
# 选择选项 (选项在 body 的 el-popper 中)
|
||||
# 等待选项出现
|
||||
await self.page.get_by_role('option', name=list_class).click()
|
||||
|
||||
await dialog.get_by_role('button', name='确 定').click()
|
||||
await self.wait_for_selector("div:has-text('新增成功')", timeout=10000)
|
||||
|
||||
async def edit_dict_data(self, label: str, remark: str) -> None:
|
||||
"""修改字典数据"""
|
||||
# 点击修改按钮
|
||||
row = self.page.locator('tbody tr').filter(has_text=label).first
|
||||
await row.get_by_role('button', name='修改').click()
|
||||
|
||||
dialog = self.page.get_by_role('dialog')
|
||||
await dialog.wait_for()
|
||||
|
||||
await dialog.get_by_role('textbox', name='备注').fill(remark)
|
||||
await dialog.get_by_role('button', name='确 定').click()
|
||||
|
||||
await self.wait_for_selector("div:has-text('修改成功')", timeout=10000)
|
||||
|
||||
async def delete_dict_data(self, label: str) -> None:
|
||||
"""删除字典数据"""
|
||||
# 点击删除按钮
|
||||
row = self.page.locator('tbody tr').filter(has_text=label).first
|
||||
await row.get_by_role('button', name='删除').click()
|
||||
|
||||
await self.page.get_by_role('button', name='确定').click()
|
||||
await self.wait_for_selector("div:has-text('删除成功')", timeout=10000)
|
||||
|
||||
async def delete_dict_type(self, dict_name: str) -> None:
|
||||
"""删除字典类型"""
|
||||
await self.search_dict_type(dict_name, '')
|
||||
|
||||
# 点击删除按钮
|
||||
row = self.page.locator('tbody tr').filter(has_text=dict_name).first
|
||||
await row.get_by_role('button', name='删除').click()
|
||||
|
||||
await self.page.get_by_role('button', name='确定').click()
|
||||
await self.wait_for_selector("div:has-text('删除成功')", timeout=10000)
|
||||
|
||||
async def test_dict_crud_operations(self) -> None:
|
||||
"""测试字典管理全流程"""
|
||||
data = self.generate_dict_data()
|
||||
|
||||
# 1. 进入字典管理
|
||||
await self.goto_page(Config.frontend_url + '/system/dict')
|
||||
# 等待页面加载
|
||||
await self.wait_for_selector('text=字典名称') # 页面标题或其他标识
|
||||
|
||||
# 2. 创建字典类型
|
||||
await self.create_dict_type(data['dict_name'], data['dict_type'])
|
||||
|
||||
# 3. 搜索并修改
|
||||
await self.edit_dict_type(data['dict_name'], data['remark'])
|
||||
|
||||
# 4. 管理字典数据
|
||||
await self.manage_dict_data(data['dict_type'], data)
|
||||
|
||||
# 5. 删除字典类型
|
||||
await self.delete_dict_type(data['dict_name'])
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_dict_management_page() -> None:
|
||||
"""测试字典管理页面功能"""
|
||||
async with async_playwright() as p:
|
||||
test_instance = DictManagementTest()
|
||||
await test_instance.setup(p)
|
||||
try:
|
||||
await test_instance.test_dict_crud_operations()
|
||||
finally:
|
||||
await test_instance.teardown()
|
||||
@@ -0,0 +1,138 @@
|
||||
import pytest
|
||||
from playwright.async_api import async_playwright
|
||||
|
||||
from common.base_page_test import BasePageTest
|
||||
from common.config import Config
|
||||
|
||||
|
||||
class LogManagementTest(BasePageTest):
|
||||
"""日志管理测试类"""
|
||||
|
||||
async def test_operlog_operations(self) -> None:
|
||||
"""测试操作日志查询、删除和清空"""
|
||||
# 1. 导航到操作日志页面
|
||||
# 直接访问正确的路由
|
||||
await self.page.goto(Config.frontend_url + '/system/log/operlog')
|
||||
await self.page.wait_for_load_state('networkidle')
|
||||
|
||||
try:
|
||||
await self.page.wait_for_selector('.app-container', timeout=10000)
|
||||
except Exception:
|
||||
# 如果首次加载失败,尝试刷新
|
||||
await self.page.reload()
|
||||
await self.page.wait_for_selector('.app-container', timeout=10000)
|
||||
|
||||
# 2. 查询操作
|
||||
# 输入操作人员
|
||||
await self.page.locator('div.el-form-item', has_text='操作人员').locator('input').fill('admin')
|
||||
# 点击搜索按钮
|
||||
await self.page.get_by_role('button', name='搜索').click()
|
||||
await self.page.wait_for_timeout(1000) # 等待搜索结果
|
||||
# 点击重置按钮
|
||||
await self.page.get_by_role('button', name='重置').click()
|
||||
await self.page.wait_for_timeout(1000) # 等待重置结果
|
||||
|
||||
# 3. 删除操作
|
||||
# 检查是否有数据,如果有则进行删除测试
|
||||
rows = self.page.locator('.el-table__body tr')
|
||||
count = await rows.count()
|
||||
if count > 0:
|
||||
# 选中第一条
|
||||
await rows.first.locator('.el-checkbox').click()
|
||||
# 点击删除
|
||||
await self.page.get_by_role('button', name='删除').click()
|
||||
# 确认删除
|
||||
await self.page.get_by_role('button', name='确定').click()
|
||||
# 等待删除完成提示
|
||||
try:
|
||||
await self.page.wait_for_selector('text=删除成功', timeout=10000)
|
||||
except Exception:
|
||||
pass # 可能是 toast 提示,稍纵即逝
|
||||
|
||||
# 4. 清空操作
|
||||
# 点击清空
|
||||
await self.page.get_by_role('button', name='清空').click()
|
||||
# 确认清空
|
||||
await self.page.get_by_role('button', name='确定').click()
|
||||
|
||||
# 5. 验证清空后还有一条"清空"的操作日志
|
||||
await self.page.wait_for_timeout(1000) # 等待清空操作完成并刷新
|
||||
await self.page.get_by_role('button', name='搜索').click() # 刷新列表
|
||||
await self.page.wait_for_timeout(1000)
|
||||
|
||||
# 验证列表不为空 (因为清空操作本身会产生一条日志)
|
||||
rows_after_clean = self.page.locator('.el-table__body tr')
|
||||
count_after_clean = await rows_after_clean.count()
|
||||
assert count_after_clean > 0, '操作日志清空后应该至少有一条记录(清空操作本身)'
|
||||
|
||||
# 可以在这里进一步验证第一条记录的类型是否为清空,但题目只要求不是空列表
|
||||
|
||||
async def test_logininfor_operations(self) -> None:
|
||||
"""测试登录日志查询、删除和清空"""
|
||||
# 1. 导航到登录日志页面
|
||||
await self.page.goto(Config.frontend_url + '/system/log/logininfor')
|
||||
await self.page.wait_for_load_state('networkidle')
|
||||
|
||||
try:
|
||||
await self.page.wait_for_selector('.app-container', timeout=10000)
|
||||
except Exception:
|
||||
# 如果失败,尝试刷新
|
||||
await self.page.reload()
|
||||
await self.page.wait_for_selector('.app-container', timeout=10000)
|
||||
|
||||
# 2. 查询操作
|
||||
# 输入用户名称
|
||||
await self.page.locator('div.el-form-item', has_text='用户名称').locator('input').fill('admin')
|
||||
# 点击搜索
|
||||
await self.page.get_by_role('button', name='搜索').click()
|
||||
await self.page.wait_for_timeout(1000)
|
||||
# 点击重置
|
||||
await self.page.get_by_role('button', name='重置').click()
|
||||
await self.page.wait_for_timeout(1000)
|
||||
|
||||
# 3. 删除操作
|
||||
# 检查是否有数据
|
||||
rows = self.page.locator('.el-table__body tr')
|
||||
count = await rows.count()
|
||||
if count > 0:
|
||||
# 选中第一条
|
||||
await rows.first.locator('.el-checkbox').click()
|
||||
# 点击删除
|
||||
await self.page.get_by_role('button', name='删除').click()
|
||||
# 确认删除
|
||||
await self.page.get_by_role('button', name='确定').click()
|
||||
# 等待删除成功
|
||||
try:
|
||||
await self.page.wait_for_selector('text=删除成功', timeout=10000)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 4. 清空操作
|
||||
# 点击清空
|
||||
await self.page.get_by_role('button', name='清空').click()
|
||||
# 确认清空
|
||||
await self.page.get_by_role('button', name='确定').click()
|
||||
|
||||
# 5. 验证清空后列表为空
|
||||
await self.page.wait_for_timeout(1000)
|
||||
# 检查是否显示"暂无数据"
|
||||
no_data = await self.page.get_by_text('暂无数据').is_visible()
|
||||
if not no_data:
|
||||
# 再次检查行数
|
||||
count_final = await self.page.locator('.el-table__body tr').count()
|
||||
assert count_final == 0, '登录日志清空后应该没有数据'
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_log_management_page() -> None:
|
||||
"""测试日志管理页面功能"""
|
||||
async with async_playwright() as p:
|
||||
test_instance = LogManagementTest()
|
||||
await test_instance.setup(p)
|
||||
try:
|
||||
# 运行操作日志测试
|
||||
await test_instance.test_operlog_operations()
|
||||
# 运行登录日志测试
|
||||
await test_instance.test_logininfor_operations()
|
||||
finally:
|
||||
await test_instance.teardown()
|
||||
@@ -0,0 +1,145 @@
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
from playwright.async_api import async_playwright
|
||||
|
||||
from common.base_page_test import BasePageTest
|
||||
from common.config import Config
|
||||
|
||||
|
||||
class MenuManagementTest(BasePageTest):
|
||||
"""菜单管理测试"""
|
||||
|
||||
def generate_menu_data(self) -> dict:
|
||||
"""生成测试数据"""
|
||||
timestamp = datetime.now().strftime('%H%M%S')
|
||||
return {
|
||||
'dir_name': f'测试目录_{timestamp}',
|
||||
'menu_name': f'测试菜单_{timestamp}',
|
||||
'path_dir': f'test_dir_{timestamp}',
|
||||
'path_menu': f'test_menu_{timestamp}',
|
||||
'path_menu_new': f'test_menu_new_{timestamp}',
|
||||
'order_num': '10',
|
||||
}
|
||||
|
||||
async def create_directory(self, menu_name: str, path: str, order_num: str) -> None:
|
||||
"""创建目录"""
|
||||
# 点击顶部新增按钮
|
||||
await self.page.get_by_role('button', name='新增').first.click()
|
||||
|
||||
# 等待对话框出现
|
||||
dialog = self.page.get_by_role('dialog')
|
||||
await dialog.wait_for()
|
||||
|
||||
# 填写表单
|
||||
await dialog.get_by_role('spinbutton', name='显示排序').fill(order_num)
|
||||
await dialog.get_by_role('textbox', name='菜单名称').fill(menu_name)
|
||||
await dialog.get_by_role('textbox', name='路由地址').fill(path)
|
||||
|
||||
# 提交
|
||||
await dialog.get_by_role('button', name='确 定').click()
|
||||
|
||||
# 验证成功提示
|
||||
await self.wait_for_selector("div:has-text('新增成功')", timeout=10000)
|
||||
|
||||
async def search_menu(self, menu_name: str) -> None:
|
||||
"""搜索菜单"""
|
||||
# 填写搜索条件
|
||||
# 使用 first 匹配搜索表单(通常在顶部),避免匹配到隐藏对话框中的同名字段
|
||||
await self.page.locator('form').first.get_by_role('textbox', name='菜单名称').fill(menu_name)
|
||||
await self.page.get_by_role('button', name='搜索').click()
|
||||
|
||||
# 等待表格刷新(简单等待)
|
||||
await self.page.wait_for_timeout(1000)
|
||||
|
||||
async def create_sub_menu(self, parent_name: str, menu_name: str, path: str, order_num: str) -> None:
|
||||
"""在指定目录下创建子菜单"""
|
||||
# 找到父级菜单行
|
||||
row = self.page.locator('tbody tr').filter(has_text=parent_name).first
|
||||
|
||||
# 点击行内新增按钮
|
||||
await row.get_by_role('button', name='新增').click()
|
||||
|
||||
# 等待对话框
|
||||
dialog = self.page.get_by_role('dialog')
|
||||
await dialog.wait_for()
|
||||
|
||||
# 选择菜单类型为"菜单"
|
||||
await dialog.locator('label').filter(has_text='菜单').first.click()
|
||||
|
||||
# 填写表单
|
||||
await dialog.get_by_role('spinbutton', name='显示排序').fill(order_num)
|
||||
await dialog.get_by_role('textbox', name='菜单名称').fill(menu_name)
|
||||
await dialog.get_by_role('textbox', name='路由地址').fill(path)
|
||||
|
||||
# 提交
|
||||
await dialog.get_by_role('button', name='确 定').click()
|
||||
|
||||
# 验证成功
|
||||
await self.wait_for_selector("div:has-text('新增成功')", timeout=10000)
|
||||
|
||||
async def edit_sub_menu(self, menu_name: str, new_path: str) -> None:
|
||||
"""修改子菜单"""
|
||||
# 搜索子菜单
|
||||
await self.search_menu(menu_name)
|
||||
|
||||
row = self.page.locator('tbody tr').filter(has_text=menu_name).first
|
||||
await row.get_by_role('button', name='修改').click()
|
||||
|
||||
await self.wait_for_selector('.el-dialog', timeout=5000)
|
||||
dialog = self.page.locator('.el-dialog')
|
||||
|
||||
await dialog.get_by_role('textbox', name='路由地址').fill(new_path)
|
||||
await self.page.get_by_role('button', name='确 定').click()
|
||||
|
||||
await self.wait_for_selector("div:has-text('修改成功')", timeout=10000)
|
||||
|
||||
async def delete_menus(self, menu_names: list[str]) -> None:
|
||||
"""删除菜单(列表)"""
|
||||
for name in menu_names:
|
||||
await self.search_menu(name)
|
||||
row = self.page.locator('tbody tr').filter(has_text=name).first
|
||||
|
||||
# 点击删除
|
||||
await row.get_by_role('button', name='删除').click()
|
||||
|
||||
# 确认删除
|
||||
await self.page.get_by_role('button', name='确定').click()
|
||||
|
||||
await self.wait_for_selector("div:has-text('删除成功')", timeout=10000)
|
||||
|
||||
async def test_menu_crud_operations(self) -> None:
|
||||
"""测试菜单增删改查流程"""
|
||||
data = self.generate_menu_data()
|
||||
|
||||
# 1. 进入菜单管理页面
|
||||
await self.goto_page(Config.frontend_url + '/system/menu')
|
||||
await self.wait_for_page_title('菜单管理', timeout=10000)
|
||||
|
||||
# 2. 新增目录
|
||||
await self.create_directory(data['dir_name'], data['path_dir'], data['order_num'])
|
||||
|
||||
# 3. 搜索目录并新增子菜单
|
||||
await self.search_menu(data['dir_name'])
|
||||
await self.create_sub_menu(data['dir_name'], data['menu_name'], data['path_menu'], '1')
|
||||
|
||||
# 4. 修改子菜单
|
||||
await self.edit_sub_menu(data['menu_name'], data['path_menu_new'])
|
||||
|
||||
# 5. 删除子菜单
|
||||
await self.delete_menus([data['menu_name']])
|
||||
|
||||
# 6. 删除目录
|
||||
await self.delete_menus([data['dir_name']])
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_menu_management_page() -> None:
|
||||
"""测试菜单管理页面功能"""
|
||||
async with async_playwright() as p:
|
||||
test_instance = MenuManagementTest()
|
||||
await test_instance.setup(p)
|
||||
try:
|
||||
await test_instance.test_menu_crud_operations()
|
||||
finally:
|
||||
await test_instance.teardown()
|
||||
@@ -0,0 +1,165 @@
|
||||
import re
|
||||
import time
|
||||
|
||||
import pytest
|
||||
from playwright.async_api import async_playwright
|
||||
|
||||
from common.base_page_test import BasePageTest
|
||||
from common.config import Config
|
||||
|
||||
|
||||
class NoticeManagementTest(BasePageTest):
|
||||
"""通知公告管理测试类"""
|
||||
|
||||
def generate_notice_data(self) -> dict:
|
||||
"""生成测试数据"""
|
||||
timestamp = int(time.time())
|
||||
return {
|
||||
'notice_title': f'test_notice_{timestamp}',
|
||||
'updated_title': f'updated_notice_{timestamp}',
|
||||
}
|
||||
|
||||
async def create_notice(self, notice_title: str, notice_type: int = 1, notice_content: str = '测试内容') -> None:
|
||||
"""创建通知公告"""
|
||||
# 点击新增按钮
|
||||
await self.page.get_by_role('button', name='新增').first.click()
|
||||
|
||||
# 等待对话框
|
||||
dialog = self.page.get_by_role('dialog')
|
||||
await dialog.wait_for()
|
||||
|
||||
# 填写公告信息
|
||||
await dialog.get_by_role('textbox', name='公告标题').fill(notice_title)
|
||||
|
||||
# 选择公告类型
|
||||
# 根据codegen脚本,点击下拉框触发器
|
||||
await self.page.locator('div').filter(has_text=re.compile(r'^请选择$')).nth(4).click()
|
||||
# 选择对应类型选项,1为通知,2为公告
|
||||
if notice_type == 1:
|
||||
await self.page.get_by_role('option', name='通知').click()
|
||||
else:
|
||||
await self.page.get_by_role('option', name='公告').click()
|
||||
|
||||
# 填写公告内容
|
||||
await self.page.locator('.ql-container').click()
|
||||
await self.page.locator('.ql-editor').fill(notice_content)
|
||||
|
||||
# 等待一段时间确保输入完成
|
||||
await self.page.wait_for_timeout(500)
|
||||
|
||||
# 点击确认按钮
|
||||
await self.page.get_by_role('button', name='确 定').first.click()
|
||||
|
||||
# 等待一段时间确保请求发送
|
||||
await self.page.wait_for_timeout(1000)
|
||||
|
||||
# 等待新增成功提示
|
||||
await self.wait_for_selector('div:has-text("新增成功")', timeout=10000)
|
||||
|
||||
async def search_notice(self, notice_title: str) -> None:
|
||||
"""搜索通知公告"""
|
||||
# 在查询表单中输入公告标题进行查询
|
||||
await self.page.get_by_role('textbox', name='公告标题').fill(notice_title)
|
||||
|
||||
# 点击搜索按钮
|
||||
await self.page.get_by_role('button', name='搜索').first.click()
|
||||
|
||||
# 等待搜索结果加载
|
||||
await self.page.wait_for_timeout(1000)
|
||||
|
||||
async def edit_notice(self, updated_title: str, updated_content: str = '更新的测试内容') -> None:
|
||||
"""编辑通知公告"""
|
||||
# 点击编辑按钮
|
||||
await self.page.locator('tbody').get_by_role('button', name='修改').nth(0).click()
|
||||
|
||||
# 等待对话框
|
||||
dialog = self.page.get_by_role('dialog')
|
||||
await dialog.wait_for()
|
||||
|
||||
# 修改公告标题
|
||||
await dialog.get_by_role('textbox', name='公告标题').fill(updated_title)
|
||||
|
||||
# 修改公告内容
|
||||
await self.page.locator('.ql-editor').fill(updated_content)
|
||||
|
||||
# 点击确认按钮
|
||||
await self.page.get_by_role('button', name='确 定').first.click()
|
||||
|
||||
# 等待编辑成功提示
|
||||
await self.wait_for_selector('div:has-text("修改成功")', timeout=10000)
|
||||
|
||||
async def delete_notice(self) -> None:
|
||||
"""删除通知公告"""
|
||||
# 点击删除按钮
|
||||
await self.page.locator('tbody').get_by_role('button', name='删除').nth(0).click()
|
||||
|
||||
# 确认删除
|
||||
await self.page.get_by_role('button', name='确定').first.click()
|
||||
|
||||
# 等待删除成功提示
|
||||
await self.wait_for_selector('div:has-text("删除成功")', timeout=10000)
|
||||
|
||||
# 重置查询表单,确保能看到所有公告
|
||||
await self.page.get_by_role('button', name='重置').click()
|
||||
|
||||
# 等待列表刷新
|
||||
await self.page.wait_for_timeout(1000)
|
||||
|
||||
async def test_notice_crud_operations(self) -> None:
|
||||
"""测试通知公告的增删查改功能"""
|
||||
# 访问通知公告页面
|
||||
await self.goto_page(Config.frontend_url + '/system/notice')
|
||||
|
||||
# 等待页面加载完成
|
||||
await self.wait_for_page_title('通知公告', timeout=10000)
|
||||
await self.page.wait_for_timeout(1000) # 等待列表刷新
|
||||
|
||||
# 记录初始公告数量
|
||||
initial_notice_count = await self.get_table_total_rows()
|
||||
|
||||
# 生成测试数据
|
||||
data = self.generate_notice_data()
|
||||
|
||||
# 创建公告
|
||||
await self.create_notice(data['notice_title'])
|
||||
|
||||
# 验证公告已添加到列表中
|
||||
await self.page.wait_for_timeout(1000) # 等待列表刷新
|
||||
new_notice_count = await self.get_table_total_rows()
|
||||
assert new_notice_count > initial_notice_count, '新增公告后数量应该增加'
|
||||
|
||||
# 搜索公告
|
||||
await self.search_notice(data['notice_title'])
|
||||
|
||||
# 验证搜索结果中包含新增的公告
|
||||
search_result_count = await self.get_table_total_rows()
|
||||
assert search_result_count >= 1, '搜索结果应该至少包含一个公告'
|
||||
|
||||
# 编辑公告
|
||||
await self.edit_notice(data['updated_title'])
|
||||
|
||||
# 验证编辑成功
|
||||
await self.page.wait_for_timeout(1000) # 等待列表刷新
|
||||
|
||||
# 重新搜索以验证修改结果
|
||||
await self.search_notice(data['updated_title'])
|
||||
|
||||
# 删除公告
|
||||
await self.delete_notice()
|
||||
|
||||
# 验证公告已从列表中删除
|
||||
await self.page.wait_for_timeout(1000) # 等待列表刷新
|
||||
final_notice_count = await self.get_table_total_rows()
|
||||
assert final_notice_count == initial_notice_count, '删除公告后数量应该恢复到初始值'
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_notice_management_page() -> None:
|
||||
"""测试通知公告页面功能"""
|
||||
async with async_playwright() as p:
|
||||
test_instance = NoticeManagementTest()
|
||||
await test_instance.setup(p)
|
||||
try:
|
||||
await test_instance.test_notice_crud_operations()
|
||||
finally:
|
||||
await test_instance.teardown()
|
||||
@@ -0,0 +1,136 @@
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
from playwright.async_api import async_playwright
|
||||
|
||||
from common.base_page_test import BasePageTest
|
||||
from common.config import Config
|
||||
|
||||
|
||||
class PostManagementTest(BasePageTest):
|
||||
"""岗位管理测试类"""
|
||||
|
||||
def generate_post_data(self) -> dict:
|
||||
"""生成测试数据"""
|
||||
timestamp = datetime.now().strftime('%H%M%S')
|
||||
return {
|
||||
'post_name': f'测试岗位_{timestamp}',
|
||||
'post_code': f'test_{timestamp}',
|
||||
'post_sort': '10',
|
||||
'remark': f'测试备注_{timestamp}',
|
||||
}
|
||||
|
||||
async def test_post_crud_operations(self) -> None:
|
||||
"""测试岗位增删改查流程"""
|
||||
# 1. 导航到岗位管理页面
|
||||
await self.navigate_to_post_management()
|
||||
|
||||
# 生成测试数据
|
||||
data = self.generate_post_data()
|
||||
|
||||
# 2. 新增岗位
|
||||
await self.create_post(data['post_name'], data['post_code'], data['post_sort'])
|
||||
|
||||
# 3. 搜索岗位
|
||||
await self.search_post(data['post_name'], data['post_code'])
|
||||
|
||||
# 4. 修改岗位
|
||||
await self.edit_post(data['post_name'], data['remark'])
|
||||
|
||||
# 5. 删除岗位
|
||||
await self.delete_post(data['post_name'])
|
||||
|
||||
async def navigate_to_post_management(self) -> None:
|
||||
"""导航到岗位管理"""
|
||||
# 直接导航到岗位管理页面
|
||||
await self.goto_page(Config.frontend_url + '/system/post')
|
||||
# 等待页面加载
|
||||
await self.wait_for_selector('.app-container')
|
||||
|
||||
async def create_post(self, post_name: str, post_code: str, post_sort: str) -> None:
|
||||
"""新增岗位"""
|
||||
await self.page.get_by_role('button', name='新增').click()
|
||||
|
||||
dialog = self.page.get_by_role('dialog')
|
||||
await dialog.wait_for()
|
||||
|
||||
# 填写表单
|
||||
# 注意:Element Plus 表单必填项可能有 * 号,Label 匹配可能需要注意
|
||||
await dialog.get_by_role('textbox', name='岗位名称').fill(post_name)
|
||||
await dialog.get_by_role('textbox', name='岗位编码').fill(post_code)
|
||||
|
||||
# 岗位顺序是 input-number
|
||||
# script.py 使用 spinbutton
|
||||
await dialog.get_by_role('spinbutton', name='岗位顺序').fill(post_sort)
|
||||
|
||||
await dialog.get_by_role('button', name='确 定').click()
|
||||
|
||||
# 等待成功提示
|
||||
await self.wait_for_selector("div:has-text('新增成功')", timeout=10000)
|
||||
|
||||
async def search_post(self, post_name: str, post_code: str) -> None:
|
||||
"""搜索岗位"""
|
||||
# 填写搜索表单
|
||||
# 限定在搜索区域,防止定位到弹窗或其他地方(虽然此时没有弹窗)
|
||||
search_form = self.page.locator('.el-form').first
|
||||
|
||||
await search_form.get_by_role('textbox', name='岗位编码').fill(post_code)
|
||||
await search_form.get_by_role('textbox', name='岗位名称').fill(post_name)
|
||||
|
||||
await self.page.get_by_role('button', name='搜索').click()
|
||||
|
||||
# 等待表格加载结果
|
||||
# 验证表格中包含刚创建的岗位
|
||||
await self.wait_for_selector(f"tbody tr:has-text('{post_name}')", timeout=10000)
|
||||
|
||||
async def edit_post(self, post_name: str, remark: str) -> None:
|
||||
"""修改岗位"""
|
||||
# 确保当前显示的是我们要修改的岗位
|
||||
await self.search_post(post_name, '')
|
||||
|
||||
row = self.page.locator('tbody tr').first
|
||||
# 点击修改按钮
|
||||
await row.get_by_role('button', name='修改').click()
|
||||
|
||||
dialog = self.page.get_by_role('dialog')
|
||||
await dialog.wait_for()
|
||||
|
||||
# 修改备注
|
||||
await dialog.get_by_role('textbox', name='备注').fill(remark)
|
||||
|
||||
await dialog.get_by_role('button', name='确 定').click()
|
||||
|
||||
# 等待成功提示
|
||||
await self.wait_for_selector("div:has-text('修改成功')", timeout=10000)
|
||||
|
||||
async def delete_post(self, post_name: str) -> None:
|
||||
"""删除岗位"""
|
||||
# 确保当前显示的是我们要删除的岗位
|
||||
search_form = self.page.locator('.el-form').first
|
||||
await search_form.get_by_role('textbox', name='岗位编码').clear()
|
||||
await search_form.get_by_role('textbox', name='岗位名称').fill(post_name)
|
||||
await self.page.get_by_role('button', name='搜索').click()
|
||||
|
||||
await self.wait_for_selector(f"tbody tr:has-text('{post_name}')", timeout=10000)
|
||||
|
||||
row = self.page.locator('tbody tr').first
|
||||
# 点击删除按钮
|
||||
await row.get_by_role('button', name='删除').click()
|
||||
|
||||
# 确认删除
|
||||
await self.page.get_by_role('button', name='确定').click()
|
||||
|
||||
# 等待成功提示
|
||||
await self.wait_for_selector("div:has-text('删除成功')", timeout=10000)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_post_management_page() -> None:
|
||||
"""测试岗位管理页面功能"""
|
||||
async with async_playwright() as p:
|
||||
test_instance = PostManagementTest()
|
||||
await test_instance.setup(p)
|
||||
try:
|
||||
await test_instance.test_post_crud_operations()
|
||||
finally:
|
||||
await test_instance.teardown()
|
||||
@@ -0,0 +1,148 @@
|
||||
import time
|
||||
|
||||
import pytest
|
||||
from playwright.async_api import async_playwright
|
||||
|
||||
from common.base_page_test import BasePageTest
|
||||
from common.config import Config
|
||||
|
||||
|
||||
class RoleManagementTest(BasePageTest):
|
||||
"""角色管理测试类"""
|
||||
|
||||
def generate_role_data(self) -> dict:
|
||||
"""生成测试数据"""
|
||||
timestamp = int(time.time())
|
||||
return {
|
||||
'role_name': f'test_role_{timestamp}',
|
||||
'role_key': f'test_{timestamp}',
|
||||
}
|
||||
|
||||
async def create_role(self, role_name: str, role_key: str, role_sort: int = 3) -> None:
|
||||
"""创建角色"""
|
||||
# 点击新增按钮
|
||||
await self.page.get_by_role('button', name='新增').click()
|
||||
|
||||
# 等待对话框
|
||||
dialog = self.page.get_by_role('dialog')
|
||||
await dialog.wait_for()
|
||||
|
||||
# 填写信息
|
||||
await dialog.get_by_role('textbox', name='角色名称').fill(role_name)
|
||||
await dialog.get_by_role('textbox', name='权限字符').fill(role_key)
|
||||
await dialog.get_by_role('spinbutton', name='角色顺序').fill(str(role_sort))
|
||||
|
||||
# 选择菜单权限 (点击第一个复选框)
|
||||
await self.page.locator('.el-tree-node__content .el-checkbox').first.click()
|
||||
|
||||
# 确定
|
||||
await self.page.get_by_role('button', name='确 定').click()
|
||||
|
||||
# 等待成功提示
|
||||
await self.wait_for_selector('div:has-text("新增成功")', timeout=10000)
|
||||
|
||||
async def search_role(self, role_name: str, role_key: str) -> None:
|
||||
"""搜索角色"""
|
||||
search_form = self.page.locator('form').first
|
||||
await search_form.get_by_placeholder('请输入角色名称').fill(role_name)
|
||||
await search_form.get_by_placeholder('请输入权限字符').fill(role_key)
|
||||
await search_form.get_by_role('button', name='搜索').click()
|
||||
|
||||
# 等待加载
|
||||
await self.page.wait_for_timeout(1000)
|
||||
|
||||
async def edit_role(self, new_remark: str) -> None:
|
||||
"""编辑角色"""
|
||||
# 点击修改按钮 (第一行)
|
||||
# 按钮没有文字,只有图标,所以使用 nth(0)
|
||||
row = self.page.locator('tbody tr').first
|
||||
await row.get_by_role('button').nth(0).click()
|
||||
|
||||
dialog = self.page.get_by_role('dialog')
|
||||
await dialog.wait_for()
|
||||
|
||||
# 修改备注
|
||||
await dialog.get_by_role('textbox', name='备注').fill(new_remark)
|
||||
|
||||
# 确定
|
||||
await self.page.get_by_role('button', name='确 定').click()
|
||||
|
||||
# 等待成功提示
|
||||
await self.wait_for_selector('div:has-text("修改成功")', timeout=10000)
|
||||
|
||||
async def change_role_status(self) -> None:
|
||||
"""修改角色状态"""
|
||||
# 点击开关 (第一行)
|
||||
# 使用 .el-switch__core 或者 role=switch
|
||||
# script.py uses .el-switch__action, let's try .el-switch
|
||||
switch = self.page.locator('.el-switch').first
|
||||
await switch.click()
|
||||
|
||||
# 确认对话框
|
||||
await self.page.get_by_role('button', name='确定').click()
|
||||
await self.wait_for_selector('div:has-text("成功")', timeout=5000)
|
||||
|
||||
# 再次点击恢复
|
||||
await self.page.wait_for_timeout(1000)
|
||||
await switch.click()
|
||||
await self.page.get_by_role('button', name='确定').click()
|
||||
await self.wait_for_selector('div:has-text("成功")', timeout=5000)
|
||||
|
||||
async def delete_role(self) -> None:
|
||||
"""删除角色"""
|
||||
# 点击删除按钮 (第一行第二个按钮)
|
||||
row = self.page.locator('tbody tr').first
|
||||
await row.get_by_role('button').nth(1).click()
|
||||
|
||||
# 确认删除
|
||||
await self.page.get_by_role('button', name='确定').click()
|
||||
|
||||
# 等待成功提示
|
||||
await self.wait_for_selector('div:has-text("删除成功")', timeout=10000)
|
||||
|
||||
# 重置搜索
|
||||
await self.page.get_by_role('button', name='重置').click()
|
||||
await self.page.wait_for_timeout(1000)
|
||||
|
||||
async def test_role_crud_operations(self) -> None:
|
||||
"""测试角色管理CRUD"""
|
||||
# 访问页面
|
||||
await self.goto_page(Config.frontend_url + '/system/role')
|
||||
await self.wait_for_page_title('角色管理', timeout=10000)
|
||||
|
||||
# 生成测试数据
|
||||
data = self.generate_role_data()
|
||||
|
||||
# 1. 新增
|
||||
await self.create_role(data['role_name'], data['role_key'])
|
||||
|
||||
# 验证新增结果
|
||||
await self.search_role(data['role_name'], data['role_key'])
|
||||
rows = await self.get_table_total_rows()
|
||||
assert rows >= 1, '新增后搜索应有结果'
|
||||
|
||||
# 2. 修改状态
|
||||
await self.change_role_status()
|
||||
|
||||
# 3. 编辑
|
||||
await self.edit_role('Updated remark')
|
||||
|
||||
# 4. 删除
|
||||
await self.delete_role()
|
||||
|
||||
# 验证删除结果
|
||||
await self.search_role(data['role_name'], data['role_key'])
|
||||
rows_after = await self.get_table_total_rows()
|
||||
assert rows_after == 0, '删除后搜索应无结果'
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_role_management_page() -> None:
|
||||
"""测试角色管理页面功能"""
|
||||
async with async_playwright() as p:
|
||||
test_instance = RoleManagementTest()
|
||||
await test_instance.setup(p)
|
||||
try:
|
||||
await test_instance.test_role_crud_operations()
|
||||
finally:
|
||||
await test_instance.teardown()
|
||||
@@ -0,0 +1,170 @@
|
||||
import time
|
||||
|
||||
import pytest
|
||||
from playwright.async_api import async_playwright
|
||||
|
||||
from common.base_page_test import BasePageTest
|
||||
from common.config import Config
|
||||
|
||||
|
||||
class UserManagementTest(BasePageTest):
|
||||
"""用户管理测试类"""
|
||||
|
||||
def generate_user_data(self) -> dict:
|
||||
"""生成测试数据"""
|
||||
timestamp = int(time.time())
|
||||
return {
|
||||
'user_name': f'test_{timestamp}',
|
||||
'nick_name': f'测试用户_{timestamp}',
|
||||
'phone': '13888888888',
|
||||
}
|
||||
|
||||
async def create_user(self, user_name: str, nick_name: str, phone: str) -> None:
|
||||
"""创建用户"""
|
||||
# 点击新增按钮
|
||||
await self.page.get_by_role('button', name='新增').click()
|
||||
|
||||
# 等待对话框
|
||||
dialog = self.page.get_by_role('dialog')
|
||||
await dialog.wait_for()
|
||||
|
||||
# 填写基本信息
|
||||
await dialog.get_by_role('textbox', name='用户昵称').fill(nick_name)
|
||||
|
||||
# 归属部门
|
||||
# 使用 label 定位父级 form-item,再点击内部的 wrapper
|
||||
await dialog.locator('div.el-form-item').filter(has_text='归属部门').locator('.el-select__wrapper').click()
|
||||
# 选择 "集团总公司" (根节点)
|
||||
# 使用 .el-popper 定位下拉框中的内容
|
||||
await self.page.locator('.el-popper:visible').get_by_text('集团总公司').click()
|
||||
|
||||
await dialog.get_by_role('textbox', name='用户名称').fill(user_name)
|
||||
# 手机号码在搜索框也有,所以必须限定在 dialog 内
|
||||
# 注意:有些 label 可能不带 *,或者带 * 但 get_by_role 需要准确匹配
|
||||
# 这里使用 get_by_placeholder 或者 filter 来定位更稳妥,或者直接 scope 到 dialog
|
||||
await dialog.locator('div.el-form-item').filter(has_text='手机号码').get_by_role('textbox').fill(phone)
|
||||
await dialog.locator('div.el-form-item').filter(has_text='邮箱').get_by_role('textbox').fill('test@example.com')
|
||||
await dialog.locator('div.el-form-item').filter(has_text='用户密码').get_by_role('textbox').fill('123456')
|
||||
|
||||
# 用户性别
|
||||
# 定位 label 为 "用户性别" 的父级 form-item,然后找里面的 "请选择" 文本
|
||||
await dialog.locator('div.el-form-item').filter(has_text='用户性别').get_by_text('请选择').click()
|
||||
await self.page.get_by_role('option', name='男').click()
|
||||
|
||||
# 岗位
|
||||
await dialog.locator('div.el-form-item').filter(has_text='岗位').get_by_text('请选择').click()
|
||||
await self.page.get_by_role('option', name='董事长').click()
|
||||
|
||||
# 角色
|
||||
await dialog.locator('div.el-form-item').filter(has_text='角色').get_by_text('请选择').click()
|
||||
await self.page.get_by_role('option', name='普通角色').click()
|
||||
|
||||
await dialog.locator('div.el-form-item').filter(has_text='备注').get_by_role('textbox').fill('测试用户')
|
||||
|
||||
# 点击确定
|
||||
await self.page.get_by_role('button', name='确 定').click()
|
||||
# 等待成功消息
|
||||
await self.wait_for_selector("div:has-text('成功')", timeout=10000)
|
||||
|
||||
async def search_user(self, user_name: str) -> None:
|
||||
"""搜索用户"""
|
||||
search_form = self.page.locator('form').first
|
||||
await search_form.get_by_role('textbox', name='用户名称').fill(user_name)
|
||||
await search_form.get_by_role('button', name='搜索').click()
|
||||
|
||||
# 等待加载
|
||||
await self.page.wait_for_timeout(1000)
|
||||
|
||||
async def edit_user(self) -> None:
|
||||
"""编辑用户"""
|
||||
# 点击修改按钮 (第一行)
|
||||
row = self.page.locator('tbody tr').first
|
||||
await row.get_by_role('button').nth(0).click()
|
||||
|
||||
dialog = self.page.get_by_role('dialog')
|
||||
await dialog.wait_for()
|
||||
|
||||
# 修改性别为女
|
||||
await dialog.locator('div.el-form-item').filter(has_text='用户性别').locator('.el-select').click()
|
||||
await self.page.get_by_role('option', name='女').click()
|
||||
|
||||
# 确定
|
||||
await self.page.get_by_role('button', name='确 定').click()
|
||||
|
||||
# 等待成功提示
|
||||
await self.wait_for_selector('div:has-text("修改成功")', timeout=10000)
|
||||
|
||||
async def change_user_status(self) -> None:
|
||||
"""修改用户状态"""
|
||||
# 点击开关 (第一行)
|
||||
switch = self.page.locator('.el-switch').first
|
||||
await switch.click()
|
||||
|
||||
# 确认对话框
|
||||
await self.page.get_by_role('button', name='确定').click()
|
||||
await self.wait_for_selector('div:has-text("成功")', timeout=5000)
|
||||
|
||||
# 再次点击恢复
|
||||
await self.page.wait_for_timeout(1000)
|
||||
await switch.click()
|
||||
await self.page.get_by_role('button', name='确定').click()
|
||||
await self.wait_for_selector('div:has-text("成功")', timeout=5000)
|
||||
|
||||
async def delete_user(self) -> None:
|
||||
"""删除用户"""
|
||||
# 点击删除按钮 (第一行第二个按钮)
|
||||
row = self.page.locator('tbody tr').first
|
||||
await row.get_by_role('button').nth(1).click()
|
||||
|
||||
# 确认删除
|
||||
await self.page.get_by_role('button', name='确定').click()
|
||||
|
||||
# 等待成功提示
|
||||
await self.wait_for_selector('div:has-text("删除成功")', timeout=10000)
|
||||
|
||||
# 重置搜索
|
||||
await self.page.get_by_role('button', name='重置').click()
|
||||
await self.page.wait_for_timeout(1000)
|
||||
|
||||
async def test_user_crud_operations(self) -> None:
|
||||
"""测试用户管理增删查改"""
|
||||
# 访问页面
|
||||
await self.goto_page(Config.frontend_url + '/system/user')
|
||||
await self.wait_for_page_title('用户管理', timeout=10000)
|
||||
|
||||
# 生成测试数据
|
||||
data = self.generate_user_data()
|
||||
|
||||
# 1. 新增
|
||||
await self.create_user(data['user_name'], data['nick_name'], data['phone'])
|
||||
|
||||
# 验证新增结果
|
||||
await self.search_user(data['user_name'])
|
||||
rows = await self.get_table_total_rows()
|
||||
assert rows >= 1, '新增后搜索应有结果'
|
||||
|
||||
# 2. 修改状态
|
||||
await self.change_user_status()
|
||||
|
||||
# 3. 编辑
|
||||
await self.edit_user()
|
||||
|
||||
# 4. 删除
|
||||
await self.delete_user()
|
||||
|
||||
# 验证删除结果
|
||||
await self.search_user(data['user_name'])
|
||||
rows_after = await self.get_table_total_rows()
|
||||
assert rows_after == 0, '删除后搜索应无结果'
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_user_management_page() -> None:
|
||||
"""测试用户管理页面功能"""
|
||||
async with async_playwright() as p:
|
||||
test_instance = UserManagementTest()
|
||||
await test_instance.setup(p)
|
||||
try:
|
||||
await test_instance.test_user_crud_operations()
|
||||
finally:
|
||||
await test_instance.teardown()
|
||||
Reference in New Issue
Block a user