ShiErFeng/shierfeng-fastapi-test/tool/test_code_gen.py
2026-07-24 09:43:10 +08:00

229 lines
8.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import re
import pytest
from playwright.async_api import async_playwright, expect
from common.base_page_test import BasePageTest
from common.config import Config
class GenTableTest(BasePageTest):
"""代码生成业务测试"""
async def test_gen_code_flow(self) -> None:
"""测试代码生成全流程:导入 -> 编辑 -> 预览 -> 删除"""
table_name = 'sys_post'
# 1. 导航到代码生成页面
await self.navigate_to_gen_page()
# 确保环境清理 (如果存在 sys_post 则先删除)
await self.ensure_table_not_exists(table_name)
# 2. 导入表
await self.import_table(table_name)
# 3. 编辑表
await self.edit_table(table_name, '测试生成')
# 4. 预览代码
await self.preview_code(table_name)
await self.page.wait_for_timeout(1000)
# 5. 删除表 (清理环境)
await self.delete_table(table_name)
async def navigate_to_gen_page(self) -> None:
"""导航到代码生成页面"""
await self.goto_page(Config.frontend_url + '/tool/gen')
await self.wait_for_selector('.app-container')
async def ensure_table_not_exists(self, table_name: str) -> None:
"""确保表不存在 (如果存在则删除)"""
await self.delete_table(table_name, verify=False)
async def search_table(self, table_name: str) -> None:
"""搜索表"""
# 确保在主搜索表单中搜索
search_form = self.page.locator('.el-form').first
await search_form.get_by_role('textbox', name='表名称').fill(table_name)
await search_form.get_by_role('button', name='搜索').click()
# 等待加载
loading = self.page.locator('.el-loading-mask')
if await loading.count() > 0:
await expect(loading.first).to_be_hidden(timeout=10000)
await self.page.wait_for_timeout(300)
async def import_table(self, table_name: str) -> None:
"""导入表"""
await self.page.get_by_role('button', name='导入').click()
dialog = self.page.locator("div[role='dialog'][aria-label='导入表']")
await dialog.wait_for()
# 搜索要导入的表
await dialog.get_by_placeholder('请输入表名称').fill(table_name)
await dialog.get_by_role('button', name='搜索').click()
# 等待搜索结果
await dialog.locator(f"tr:has-text('{table_name}')").wait_for()
# 选中行
row = dialog.locator('tr').filter(has=self.page.get_by_text(table_name, exact=True))
# 点击复选框
checkbox = row.locator('.el-checkbox')
await checkbox.click()
# 验证已选中
# Element Plus checkbox 选中时,最外层 label.el-checkbox 会有 is-checked 类
await expect(checkbox).to_have_class(re.compile(r'is-checked'))
await self.page.wait_for_timeout(500)
await dialog.get_by_role('button', name='确 定').click()
# 检查是否有"请选择要导入的表"错误
try:
await expect(self.page.get_by_text('请选择要导入的表')).to_be_visible(timeout=2000)
print("ERROR: Selection failed, '请选择要导入的表' appeared.")
except AssertionError:
pass
# 等待一会,让弹窗自动关闭
await self.page.wait_for_timeout(5000)
# 如果弹窗还在,尝试关闭它以免阻塞后续操作
if await dialog.is_visible():
print('WARNING: Import dialog still visible after timeout. Forcing close.')
# Check for error messages
if await self.page.locator('.el-message--error').count() > 0:
msg = await self.page.locator('.el-message--error').all_inner_texts()
print(f'ERROR MESSAGE: {msg}')
# 点击取消关闭弹窗
await dialog.get_by_role('button', name='取 消').click()
await expect(dialog).to_be_hidden()
# 手动刷新列表
await self.page.get_by_role('button', name='搜索').click()
# 验证导入成功 (搜索并在列表中看到)
# 使用 .app-container 限定在主页面表格,避免匹配到弹窗中的隐藏行
await self.search_table(table_name)
row = self.page.locator('.app-container .el-table__body-wrapper tbody tr').filter(
has=self.page.get_by_text(table_name, exact=True)
)
for _i in range(5):
try:
await expect(row.first).to_be_visible(timeout=3000)
break
except AssertionError:
await self.search_table(table_name)
await expect(row.first).to_be_visible(timeout=5000)
async def edit_table(self, table_name: str, remark: str) -> None:
"""编辑表"""
await self.search_table(table_name)
row = self.page.locator(f"tbody tr:has-text('{table_name}')")
# 点击编辑 (操作列第2个按钮索引1)
# 按钮顺序: 预览, 编辑, 删除, 同步, 生成
await row.locator('button').nth(1).click()
# 等待编辑页面 (tab页)
await self.page.wait_for_selector("div[role='tablist']")
# 修改基本信息 -> 表描述
# 确保在基本信息 Tab
await self.page.get_by_text('基本信息').click()
await self.page.get_by_role('textbox', name='表描述').fill(remark)
# 提交
await self.page.get_by_role('button', name='提交').click()
# 验证回到列表
await self.wait_for_selector('.app-container')
# 验证描述已更新
await self.search_table(table_name)
await self.wait_for_selector(f"tbody tr:has-text('{remark}')")
async def preview_code(self, table_name: str) -> None:
"""预览代码"""
await self.search_table(table_name)
row = self.page.locator(f"tbody tr:has-text('{table_name}')")
# 点击预览 (操作列第1个按钮索引0)
await row.locator('button').nth(0).click()
# 等待预览弹窗
dialog = self.page.locator("div[role='dialog'][aria-label='代码预览']")
await dialog.wait_for()
# 验证存在代码内容
# pre 可能有多个多tab只检查可见的
await dialog.locator('pre:visible').first.wait_for()
content = await dialog.locator('pre:visible').first.text_content()
assert 'class' in content or 'import' in content or 'package' in content
# 关闭预览 (点击右上角关闭按钮)
await dialog.locator('.el-dialog__headerbtn').click()
async def delete_table(self, table_name: str, verify: bool = True) -> None:
"""删除表 (支持删除多条重复数据)"""
# 循环删除直到不存在
for _i in range(5):
await self.search_table(table_name)
# 使用 strict matching
# 限制在 .app-container .el-table__body-wrapper 以避免固定列导致的重复 以及 避免匹配到弹窗中的行
row = self.page.locator('.app-container .el-table__body-wrapper tbody tr').filter(
has=self.page.get_by_text(table_name, exact=True)
)
count = await row.count()
if count == 0:
break
# 针对第一行操作
# 使用 force=True 确保点击,防止遮挡
btns = row.first.locator('button')
await btns.nth(2).click(force=True)
# 处理确认弹窗
await self.page.get_by_role('button', name='确定').click()
# 等待删除成功提示
# 使用 specific selector 避免匹配到代码预览中的文本
await expect(self.page.locator('.el-message__content').filter(has_text='删除成功')).to_be_visible(
timeout=5000
)
# 等待提示消失,防止干扰下一次操作
await expect(self.page.locator('.el-message__content').filter(has_text='删除成功')).to_be_hidden(
timeout=5000
)
if verify:
# 验证删除成功
# 重新搜索验证不存在
await self.search_table(table_name)
# 使用 strict matching
row = self.page.locator('.app-container .el-table__body-wrapper tbody tr').filter(
has=self.page.get_by_text(table_name, exact=True)
)
# 期望找不到或者 count为0
await expect(row).to_have_count(0)
@pytest.mark.asyncio
async def test_gen_table_page() -> None:
"""测试代码生成页面功能"""
async with async_playwright() as p:
test_instance = GenTableTest()
await test_instance.setup(p)
try:
await test_instance.test_gen_code_flow()
finally:
await test_instance.teardown()