初始提交
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
import pytest
|
||||
from playwright.async_api import async_playwright, expect
|
||||
|
||||
from common.base_page_test import BasePageTest
|
||||
from common.config import Config
|
||||
|
||||
|
||||
class CacheListTest(BasePageTest):
|
||||
"""缓存列表测试类"""
|
||||
|
||||
async def test_cache_list(self) -> None:
|
||||
"""测试缓存列表页面"""
|
||||
await self.page.goto(Config.frontend_url + '/monitor/cacheList')
|
||||
await self.page.wait_for_load_state('networkidle')
|
||||
|
||||
# 1. 缓存列表 - 点击 sys_config
|
||||
await self.page.wait_for_selector('text=缓存列表')
|
||||
|
||||
# 等待 sys_config 出现并点击
|
||||
sys_config_row = self.page.locator('.el-card', has_text='缓存列表').locator('tr', has_text='sys_config')
|
||||
await sys_config_row.wait_for()
|
||||
await sys_config_row.click()
|
||||
|
||||
# 2. 键名列表 - 点击 sys.account.captchaEnabled
|
||||
await self.page.wait_for_selector('text=键名列表')
|
||||
|
||||
# 等待 sys.account.captchaEnabled 出现并点击
|
||||
captcha_row = self.page.locator('.el-card', has_text='键名列表').locator(
|
||||
'tr', has_text='sys.account.captchaEnabled'
|
||||
)
|
||||
await captcha_row.wait_for()
|
||||
await captcha_row.click()
|
||||
|
||||
# 3. 验证缓存内容为 false
|
||||
await self.page.wait_for_selector('text=缓存内容')
|
||||
|
||||
# 等待数据加载
|
||||
await self.page.wait_for_timeout(2000)
|
||||
|
||||
# 获取内容
|
||||
# 缓存内容显示在一个 textarea 中
|
||||
content_area = self.page.locator('div.el-form-item', has_text='缓存内容:').locator('textarea')
|
||||
|
||||
# 也可以尝试直接获取 .el-form-item__content 的文本,如果 textarea 不可交互
|
||||
if await content_area.count() > 0:
|
||||
# 尝试等待内容不为空
|
||||
try:
|
||||
await expect(content_area).not_to_be_empty(timeout=5000)
|
||||
except TimeoutError:
|
||||
pass
|
||||
|
||||
value = await content_area.input_value()
|
||||
print(f'Cache content value: {value}')
|
||||
|
||||
# 如果为空,可能需要重新点击一下
|
||||
if not value:
|
||||
print('Value is empty, trying to click key again')
|
||||
await captcha_row.click()
|
||||
await self.page.wait_for_timeout(2000)
|
||||
value = await content_area.input_value()
|
||||
print(f'Cache content value after retry: {value}')
|
||||
|
||||
assert 'false' in value.lower(), f"Expected 'false' in cache content, got: {value}"
|
||||
else:
|
||||
# 如果不是 textarea,尝试获取文本
|
||||
content_div = self.page.locator('div.el-form-item', has_text='缓存内容:').locator('.el-form-item__content')
|
||||
value = await content_div.text_content()
|
||||
print(f'Cache content text: {value}')
|
||||
assert 'false' in value.lower(), f"Expected 'false' in cache content, got: {value}"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_cache_list_page() -> None:
|
||||
"""测试缓存列表页面功能"""
|
||||
async with async_playwright() as p:
|
||||
test_instance = CacheListTest()
|
||||
await test_instance.setup(p)
|
||||
try:
|
||||
await test_instance.test_cache_list()
|
||||
finally:
|
||||
await test_instance.teardown()
|
||||
@@ -0,0 +1,48 @@
|
||||
import pytest
|
||||
from playwright.async_api import async_playwright
|
||||
|
||||
from common.base_page_test import BasePageTest
|
||||
from common.config import Config
|
||||
|
||||
|
||||
class CacheMonitorTest(BasePageTest):
|
||||
"""缓存监控测试类"""
|
||||
|
||||
async def test_cache_monitor(self) -> None:
|
||||
"""测试缓存监控页面"""
|
||||
await self.page.goto(Config.frontend_url + '/monitor/cache')
|
||||
await self.page.wait_for_load_state('networkidle')
|
||||
|
||||
# 验证基本信息
|
||||
await self.page.wait_for_selector('text=基本信息')
|
||||
await self.page.wait_for_selector('text=Redis版本')
|
||||
await self.page.wait_for_selector('text=运行模式')
|
||||
|
||||
# 验证命令统计
|
||||
await self.page.wait_for_selector('text=命令统计')
|
||||
|
||||
# 验证内存信息
|
||||
await self.page.wait_for_selector('text=内存信息')
|
||||
|
||||
# 验证端口为 6379
|
||||
port_row = self.page.locator('tr', has_text='端口')
|
||||
try:
|
||||
await port_row.wait_for(timeout=5000)
|
||||
text = await port_row.text_content()
|
||||
assert '6379' in text, f"Expected port '6379' in row, but got: {text}"
|
||||
except Exception:
|
||||
print("Warning: '端口' row not found, checking page content")
|
||||
content = await self.page.content()
|
||||
assert '6379' in content, "Port '6379' not found in page content"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_cache_monitor_page() -> None:
|
||||
"""测试缓存监控页面功能"""
|
||||
async with async_playwright() as p:
|
||||
test_instance = CacheMonitorTest()
|
||||
await test_instance.setup(p)
|
||||
try:
|
||||
await test_instance.test_cache_monitor()
|
||||
finally:
|
||||
await test_instance.teardown()
|
||||
@@ -0,0 +1,185 @@
|
||||
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 JobManagementTest(BasePageTest):
|
||||
"""定时任务管理测试"""
|
||||
|
||||
def generate_job_data(self) -> dict:
|
||||
"""生成测试数据"""
|
||||
timestamp = datetime.now().strftime('%H%M%S')
|
||||
return {
|
||||
'job_name': f'测试任务_{timestamp}',
|
||||
'job_group': '默认',
|
||||
'job_executor': '进程池',
|
||||
'invoke_target': 'module_task.scheduler_test.job', # 必须为这个值
|
||||
'cron_expression': '0/2 * * * * ?', # 每2秒执行一次
|
||||
'new_invoke_target': 'module_task.scheduler_test.job', # 修改时也用这个
|
||||
'job_name_edit': f'测试任务_{timestamp}_edit',
|
||||
}
|
||||
|
||||
async def create_job(
|
||||
self, job_name: str, job_group: str, job_executor: str, invoke_target: str, cron_expression: 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(job_name)
|
||||
|
||||
# 选择任务分组
|
||||
await dialog.locator("label:has-text('任务分组') + div .el-select").click()
|
||||
await self.page.get_by_role('option', name=job_group).click()
|
||||
|
||||
# 选择任务执行器
|
||||
await dialog.locator("label:has-text('任务执行器') + div .el-select").click()
|
||||
await self.page.get_by_role('option', name=job_executor).click()
|
||||
|
||||
# 填写调用方法
|
||||
await dialog.get_by_role('textbox', name='调用方法').fill(invoke_target)
|
||||
|
||||
# 填写cron表达式
|
||||
await dialog.get_by_role('textbox', name='cron表达式').fill(cron_expression)
|
||||
|
||||
# 策略:如果"失败"策略等有默认值,就不管了
|
||||
|
||||
await dialog.get_by_role('button', name='确 定').click()
|
||||
await self.wait_for_selector("div:has-text('新增成功')", timeout=10000)
|
||||
|
||||
async def search_job(self, job_name: str) -> None:
|
||||
"""搜索任务"""
|
||||
# 我们可以限制在 form 里搜索
|
||||
form = self.page.locator('form').first
|
||||
await form.get_by_role('textbox', name='任务名称').fill(job_name)
|
||||
await self.page.get_by_role('button', name='搜索').click()
|
||||
await self.page.wait_for_timeout(1000) # 等待搜索结果
|
||||
|
||||
async def edit_job(self, job_name: str, new_invoke_target: str) -> None:
|
||||
"""修改任务"""
|
||||
await self.search_job(job_name)
|
||||
|
||||
# 点击修改 (在操作列)
|
||||
row = self.page.locator('tbody tr').first
|
||||
# 操作列按钮顺序: 修改, 删除, 执行一次, 详细, 日志
|
||||
await row.locator('button').nth(0).click()
|
||||
|
||||
dialog = self.page.get_by_role('dialog')
|
||||
await dialog.wait_for()
|
||||
|
||||
# 修改调用方法
|
||||
await dialog.get_by_role('textbox', name='调用方法').fill(new_invoke_target)
|
||||
|
||||
await dialog.get_by_role('button', name='确 定').click()
|
||||
await self.wait_for_selector("div:has-text('修改成功')", timeout=10000)
|
||||
|
||||
async def toggle_job_status(self, job_name: str) -> None:
|
||||
"""切换任务状态"""
|
||||
await self.search_job(job_name)
|
||||
|
||||
row = self.page.locator('tbody tr').first
|
||||
# 切换开关
|
||||
# 需要点击可见的 .el-switch 或 .el-switch__core
|
||||
await row.locator('.el-switch').click()
|
||||
|
||||
# 确认切换
|
||||
await self.page.get_by_role('button', name='确定').click()
|
||||
await self.page.wait_for_timeout(1000)
|
||||
await self.wait_for_selector("div:has-text('成功')", timeout=10000)
|
||||
|
||||
async def run_job_once(self, job_name: str) -> None:
|
||||
"""执行一次任务"""
|
||||
await self.search_job(job_name)
|
||||
|
||||
row = self.page.locator('tbody tr').first
|
||||
# 点击执行一次 (第3个按钮)
|
||||
await row.locator('button').nth(2).click()
|
||||
|
||||
# 确认执行
|
||||
await self.page.get_by_role('button', name='确定').click()
|
||||
await self.wait_for_selector("div:has-text('执行成功')", timeout=10000)
|
||||
|
||||
async def view_job_log(self, job_name: str) -> None:
|
||||
"""查看调度日志"""
|
||||
# 可以点击顶部的 "日志" 按钮,也可以点击行的 "调度日志"
|
||||
# 我们点击行的 "调度日志" (icon="Operation")
|
||||
await self.search_job(job_name)
|
||||
row = self.page.locator('tbody tr').first
|
||||
|
||||
log_btn = row.locator('button').nth(4)
|
||||
await log_btn.click()
|
||||
|
||||
# 等待跳转到日志页面 (实际上是 router push 到 /monitor/job-log)
|
||||
# 检查 URL
|
||||
await self.page.wait_for_url('**/monitor/job-log**')
|
||||
|
||||
# 验证在日志页面
|
||||
await self.wait_for_selector('text=调度日志')
|
||||
|
||||
# 关闭返回 (点击 "关闭" 按钮)
|
||||
await self.page.get_by_role('button', name='关闭').click()
|
||||
|
||||
# 等待返回任务列表
|
||||
await self.page.wait_for_url('**/monitor/job')
|
||||
|
||||
async def delete_job(self, job_name: str) -> None:
|
||||
"""删除任务"""
|
||||
await self.search_job(job_name)
|
||||
|
||||
row = self.page.locator('tbody tr').first
|
||||
# 点击删除 (第2个按钮)
|
||||
await row.locator('button').nth(1).click()
|
||||
|
||||
# 确认删除
|
||||
await self.page.get_by_role('button', name='确定').click()
|
||||
await self.wait_for_selector("div:has-text('删除成功')", timeout=10000)
|
||||
|
||||
async def test_job_crud_operations(self) -> None:
|
||||
"""测试定时任务管理全流程"""
|
||||
data = self.generate_job_data()
|
||||
|
||||
# 1. 进入定时任务页面
|
||||
await self.goto_page(Config.frontend_url + '/monitor/job')
|
||||
await self.wait_for_selector('text=任务名称')
|
||||
|
||||
# 2. 创建任务
|
||||
await self.create_job(
|
||||
data['job_name'], data['job_group'], data['job_executor'], data['invoke_target'], data['cron_expression']
|
||||
)
|
||||
|
||||
# 3. 修改任务 (修改调用方法)
|
||||
await self.edit_job(data['job_name'], data['new_invoke_target'])
|
||||
|
||||
# 4. 切换状态 (开启/关闭)
|
||||
await self.toggle_job_status(data['job_name']) # 开启
|
||||
await self.page.wait_for_timeout(1000)
|
||||
await self.toggle_job_status(data['job_name']) # 关闭
|
||||
|
||||
# 5. 执行一次
|
||||
await self.run_job_once(data['job_name'])
|
||||
|
||||
# 6. 查看日志
|
||||
await self.view_job_log(data['job_name'])
|
||||
|
||||
# 7. 删除任务
|
||||
await self.delete_job(data['job_name'])
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_job_management_page() -> None:
|
||||
"""测试定时任务管理页面功能"""
|
||||
async with async_playwright() as p:
|
||||
test_instance = JobManagementTest()
|
||||
await test_instance.setup(p)
|
||||
try:
|
||||
await test_instance.test_job_crud_operations()
|
||||
finally:
|
||||
await test_instance.teardown()
|
||||
@@ -0,0 +1,73 @@
|
||||
import pytest
|
||||
from playwright.async_api import async_playwright
|
||||
|
||||
from common.base_page_test import BasePageTest
|
||||
from common.config import Config
|
||||
|
||||
|
||||
class OnlineUserTest(BasePageTest):
|
||||
"""在线用户测试类"""
|
||||
|
||||
async def test_online_user_operations(self) -> None:
|
||||
"""测试在线用户强退"""
|
||||
# 1. 模拟 niangao 用户登录以产生在线会话
|
||||
# 使用一个新的上下文来模拟另一个用户的登录
|
||||
niangao_context = await self.browser.new_context()
|
||||
niangao_page = await niangao_context.new_page()
|
||||
|
||||
# 登录 niangao
|
||||
try:
|
||||
await niangao_page.goto(Config.frontend_url + '/login')
|
||||
await niangao_page.locator('div.el-form-item', has_text='账号').locator('input').fill('niangao')
|
||||
await niangao_page.locator('div.el-form-item', has_text='密码').locator('input').fill('admin123')
|
||||
await niangao_page.get_by_role('button', name='登 录').click()
|
||||
# 等待登录成功
|
||||
await niangao_page.wait_for_url('**/index')
|
||||
except Exception as e:
|
||||
print(f'Niangao login failed: {e}. Trying admin123')
|
||||
try:
|
||||
await niangao_page.locator('div.el-form-item', has_text='密码').locator('input').fill('123456')
|
||||
await niangao_page.get_by_role('button', name='登 录').click()
|
||||
await niangao_page.wait_for_url('**/index')
|
||||
except Exception as e2:
|
||||
print(f'Niangao login failed again: {e2}')
|
||||
|
||||
# 2. 切换回 admin (self.page) 进行操作
|
||||
await self.page.goto(Config.frontend_url + '/monitor/online')
|
||||
await self.page.wait_for_load_state('networkidle')
|
||||
|
||||
# 3. 搜索 niangao 用户
|
||||
await self.page.locator('div.el-form-item', has_text='用户名称').locator('input').fill('niangao')
|
||||
await self.page.get_by_role('button', name='搜索').click()
|
||||
await self.page.wait_for_timeout(1000)
|
||||
|
||||
# 4. 强退操作
|
||||
# 检查是否有数据
|
||||
rows = self.page.locator('.el-table__body tr')
|
||||
count = await rows.count()
|
||||
if count > 0:
|
||||
# 点击强退
|
||||
await rows.first.get_by_role('button', name='强退').click()
|
||||
# 确认
|
||||
await self.page.get_by_role('button', name='确定').click()
|
||||
# 验证
|
||||
await self.page.wait_for_selector('text=删除成功', timeout=3000)
|
||||
|
||||
# 再次搜索确认消失
|
||||
await self.page.wait_for_timeout(1000)
|
||||
await self.page.get_by_role('button', name='搜索').click()
|
||||
|
||||
# 关闭 niangao 的上下文
|
||||
await niangao_context.close()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_online_user_page() -> None:
|
||||
"""测试在线用户页面功能"""
|
||||
async with async_playwright() as p:
|
||||
test_instance = OnlineUserTest()
|
||||
await test_instance.setup(p)
|
||||
try:
|
||||
await test_instance.test_online_user_operations()
|
||||
finally:
|
||||
await test_instance.teardown()
|
||||
@@ -0,0 +1,46 @@
|
||||
import pytest
|
||||
from playwright.async_api import async_playwright
|
||||
|
||||
from common.base_page_test import BasePageTest
|
||||
from common.config import Config
|
||||
|
||||
|
||||
class ServerMonitorTest(BasePageTest):
|
||||
"""服务监控测试类"""
|
||||
|
||||
async def test_server_monitor(self) -> None:
|
||||
"""测试服务监控页面"""
|
||||
await self.page.goto(Config.frontend_url + '/monitor/server')
|
||||
await self.page.wait_for_load_state('networkidle')
|
||||
|
||||
# 验证主要板块存在
|
||||
await self.page.wait_for_selector('text=CPU')
|
||||
await self.page.wait_for_selector('text=内存')
|
||||
await self.page.wait_for_selector('text=服务器信息')
|
||||
await self.page.wait_for_selector('text=Python解释器信息')
|
||||
await self.page.wait_for_selector('text=磁盘状态')
|
||||
|
||||
# 验证项目路径为 /app
|
||||
# 尝试在表格行中查找
|
||||
project_path_row = self.page.locator('tr', has_text='项目路径')
|
||||
try:
|
||||
await project_path_row.wait_for(timeout=5000)
|
||||
text = await project_path_row.text_content()
|
||||
assert '/app' in text, f"Expected project path '/app' in row, but got: {text}"
|
||||
except Exception:
|
||||
# 如果没找到行,尝试全局搜索
|
||||
print("Warning: '项目路径' row not found, checking page content")
|
||||
content = await self.page.content()
|
||||
assert '/app' in content, "Project path '/app' not found in page content"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_server_monitor_page() -> None:
|
||||
"""测试服务监控页面功能"""
|
||||
async with async_playwright() as p:
|
||||
test_instance = ServerMonitorTest()
|
||||
await test_instance.setup(p)
|
||||
try:
|
||||
await test_instance.test_server_monitor()
|
||||
finally:
|
||||
await test_instance.teardown()
|
||||
Reference in New Issue
Block a user