feat: E2E 测试集成真实后端
- Playwright 双 webServer 模式自动启动 Go 后端 + Vite 前端 - 后端使用临时 SQLite 数据库隔离,固定端口 19026 - vite.config.ts proxy target 动态读取环境变量 - 新增 sql.js 依赖用于 SQLite 统计数据 seed - 新增 e2e/fixtures.ts 共享工具模块(API seed + SQLite seed) - 拆分测试文件 5→7(providers/models/stats/navigation/validation) - 删除旧文件 crud.spec.ts/sidebar.spec.ts/stats-cards.spec.ts - E2E 测试尚有部分用例需调试修复
This commit is contained in:
@@ -1,8 +1,13 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { test, expect } from '@playwright/test'
|
||||
|
||||
let uid = Date.now()
|
||||
|
||||
function nextId() {
|
||||
return `pw_${++uid}`
|
||||
}
|
||||
|
||||
// 辅助:在对话框内定位输入框(TDesign Dialog + Form)
|
||||
function formInputs(page: import('@playwright/test').Page) {
|
||||
const dialog = page.locator('.t-dialog:visible');
|
||||
const dialog = page.locator('.t-dialog:visible')
|
||||
return {
|
||||
id: dialog.locator('input[placeholder="例如: openai"]'),
|
||||
name: dialog.locator('input[placeholder="例如: OpenAI"]'),
|
||||
@@ -10,126 +15,89 @@ function formInputs(page: import('@playwright/test').Page) {
|
||||
baseUrl: dialog.locator('input[placeholder="例如: https://api.openai.com/v1"]'),
|
||||
saveBtn: dialog.locator('.t-dialog__footer').getByRole('button', { name: '保存' }),
|
||||
cancelBtn: dialog.locator('.t-dialog__footer').getByRole('button', { name: '取消' }),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
test.describe('供应商管理', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/providers');
|
||||
await expect(page.getByRole('heading', { name: '供应商管理' })).toBeVisible();
|
||||
});
|
||||
await page.goto('/providers')
|
||||
await expect(page.getByRole('heading', { name: '供应商管理' })).toBeVisible()
|
||||
})
|
||||
|
||||
test('应显示供应商管理页面', async ({ page }) => {
|
||||
await expect(page.getByText('供应商列表')).toBeVisible();
|
||||
});
|
||||
test('应能创建供应商并验证出现在表格中', async ({ page }) => {
|
||||
const testId = nextId()
|
||||
await page.getByRole('button', { name: '添加供应商' }).click()
|
||||
await expect(page.locator('.t-dialog:visible')).toBeVisible()
|
||||
|
||||
test('应显示添加供应商按钮', async ({ page }) => {
|
||||
await expect(page.getByRole('button', { name: '添加供应商' })).toBeVisible();
|
||||
});
|
||||
const inputs = formInputs(page)
|
||||
await inputs.id.fill(testId)
|
||||
await inputs.name.fill('Test Provider')
|
||||
await inputs.apiKey.fill('sk_test_key_12345')
|
||||
await inputs.baseUrl.fill('https://api.openai.com/v1')
|
||||
|
||||
test('应通过侧边栏导航切换页面', async ({ page }) => {
|
||||
await page.locator('aside').getByText('用量统计').click();
|
||||
await expect(page.getByRole('heading', { name: '用量统计' })).toBeVisible();
|
||||
await inputs.saveBtn.click()
|
||||
await expect(page.locator('.t-dialog:visible')).not.toBeVisible({ timeout: 5000 })
|
||||
|
||||
await page.locator('aside').getByText('供应商管理').click();
|
||||
await expect(page.getByRole('heading', { name: '供应商管理' })).toBeVisible();
|
||||
});
|
||||
await expect(page.locator('.t-table__body td').getByText(testId)).toBeVisible()
|
||||
await expect(page.locator('.t-table__body td').getByText('Test Provider')).toBeVisible()
|
||||
})
|
||||
|
||||
test('应能打开添加供应商对话框', async ({ page }) => {
|
||||
await page.getByRole('button', { name: '添加供应商' }).click();
|
||||
test('应能编辑供应商并验证更新生效', async ({ page }) => {
|
||||
const testId = nextId()
|
||||
await page.getByRole('button', { name: '添加供应商' }).click()
|
||||
await expect(page.locator('.t-dialog:visible')).toBeVisible()
|
||||
const inputs = formInputs(page)
|
||||
await inputs.id.fill(testId)
|
||||
await inputs.name.fill('Before Edit')
|
||||
await inputs.apiKey.fill('sk_key')
|
||||
await inputs.baseUrl.fill('https://api.example.com/v1')
|
||||
await inputs.saveBtn.click()
|
||||
await expect(page.locator('.t-dialog:visible')).not.toBeVisible({ timeout: 5000 })
|
||||
|
||||
const dialog = page.locator('.t-dialog');
|
||||
await expect(dialog).toBeVisible();
|
||||
await expect(dialog.getByText('添加供应商')).toBeVisible();
|
||||
await expect(formInputs(page).id).toBeVisible();
|
||||
await expect(formInputs(page).name).toBeVisible();
|
||||
await expect(formInputs(page).apiKey).toBeVisible();
|
||||
await expect(formInputs(page).baseUrl).toBeVisible();
|
||||
});
|
||||
await page.locator('.t-table__body button:has-text("编辑")').first().click()
|
||||
await expect(page.locator('.t-dialog:visible')).toBeVisible()
|
||||
|
||||
test('应验证供应商表单必填字段', async ({ page }) => {
|
||||
await page.getByRole('button', { name: '添加供应商' }).click();
|
||||
await expect(page.locator('.t-dialog')).toBeVisible();
|
||||
const editInputs = formInputs(page)
|
||||
await editInputs.name.clear()
|
||||
await editInputs.name.fill('After Edit')
|
||||
await editInputs.saveBtn.click()
|
||||
await expect(page.locator('.t-dialog:visible')).not.toBeVisible({ timeout: 5000 })
|
||||
|
||||
await formInputs(page).saveBtn.click();
|
||||
await expect(page.locator('.t-table__body td').getByText('After Edit')).toBeVisible()
|
||||
})
|
||||
|
||||
await expect(page.getByText('请输入供应商 ID')).toBeVisible();
|
||||
await expect(page.getByText('请输入名称')).toBeVisible();
|
||||
await expect(page.getByText('请输入 API Key')).toBeVisible();
|
||||
await expect(page.getByText('请输入 Base URL')).toBeVisible();
|
||||
});
|
||||
test('应能删除供应商并验证消失', async ({ page }) => {
|
||||
const testId = nextId()
|
||||
await page.getByRole('button', { name: '添加供应商' }).click()
|
||||
await expect(page.locator('.t-dialog:visible')).toBeVisible()
|
||||
const inputs = formInputs(page)
|
||||
await inputs.id.fill(testId)
|
||||
await inputs.name.fill('To Delete')
|
||||
await inputs.apiKey.fill('sk_key')
|
||||
await inputs.baseUrl.fill('https://api.example.com/v1')
|
||||
await inputs.saveBtn.click()
|
||||
await expect(page.locator('.t-dialog:visible')).not.toBeVisible({ timeout: 5000 })
|
||||
|
||||
test('应验证URL格式', async ({ page }) => {
|
||||
await page.getByRole('button', { name: '添加供应商' }).click();
|
||||
await expect(page.locator('.t-dialog')).toBeVisible();
|
||||
await page.locator('.t-table__body button:has-text("删除")').first().click()
|
||||
await expect(page.getByText('确定要删除这个供应商吗?')).toBeVisible()
|
||||
await page.locator('.t-popconfirm').getByRole('button', { name: '确定' }).click()
|
||||
await expect(page.getByText('确定要删除这个供应商吗?')).not.toBeVisible({ timeout: 3000 })
|
||||
|
||||
const inputs = formInputs(page);
|
||||
await inputs.id.fill('test-provider');
|
||||
await inputs.name.fill('Test Provider');
|
||||
await inputs.apiKey.fill('sk-test-key');
|
||||
await inputs.baseUrl.fill('invalid-url');
|
||||
await expect(page.locator('.t-table__body td').getByText(testId)).not.toBeVisible({ timeout: 5000 })
|
||||
})
|
||||
|
||||
await inputs.saveBtn.click();
|
||||
test('应正确脱敏显示 API Key', async ({ page }) => {
|
||||
const testId = nextId()
|
||||
await page.getByRole('button', { name: '添加供应商' }).click()
|
||||
await expect(page.locator('.t-dialog:visible')).toBeVisible()
|
||||
const inputs = formInputs(page)
|
||||
await inputs.id.fill(testId)
|
||||
await inputs.name.fill('Mask Test')
|
||||
await inputs.apiKey.fill('sk_abcdefghijklmnopqrstuvwxyz')
|
||||
await inputs.baseUrl.fill('https://api.example.com/v1')
|
||||
await inputs.saveBtn.click()
|
||||
await expect(page.locator('.t-dialog:visible')).not.toBeVisible({ timeout: 5000 })
|
||||
|
||||
await expect(page.getByText('请输入有效的 URL')).toBeVisible();
|
||||
});
|
||||
|
||||
test('应能取消添加供应商', async ({ page }) => {
|
||||
await page.getByRole('button', { name: '添加供应商' }).click();
|
||||
await expect(page.locator('.t-dialog')).toBeVisible();
|
||||
|
||||
await formInputs(page).id.fill('test-provider');
|
||||
await formInputs(page).cancelBtn.click();
|
||||
|
||||
await expect(page.locator('.t-dialog')).not.toBeVisible();
|
||||
});
|
||||
|
||||
test('应显示供应商列表中的信息', async ({ page }) => {
|
||||
await expect(page.locator('.t-table')).toBeVisible();
|
||||
const tableHeaders = page.locator('.t-table__header th');
|
||||
const count = await tableHeaders.count();
|
||||
expect(count).toBeGreaterThanOrEqual(3);
|
||||
});
|
||||
|
||||
test('应能展开供应商查看模型列表', async ({ page }) => {
|
||||
const expandBtns = page.locator('.t-table__expandable-icon');
|
||||
const count = await expandBtns.count();
|
||||
|
||||
if (count > 0) {
|
||||
await expandBtns.first().click();
|
||||
await expect(page.locator('.t-table__expanded-row').first()).toBeVisible();
|
||||
} else {
|
||||
test.skip();
|
||||
}
|
||||
});
|
||||
|
||||
test('应能打开编辑供应商对话框', async ({ page }) => {
|
||||
const editBtns = page.locator('.t-table__body button:has-text("编辑")');
|
||||
const count = await editBtns.count();
|
||||
|
||||
if (count > 0) {
|
||||
await editBtns.first().click();
|
||||
const dialog = page.locator('.t-dialog');
|
||||
await expect(dialog).toBeVisible();
|
||||
await expect(dialog.getByText('编辑供应商')).toBeVisible();
|
||||
await expect(formInputs(page).id).toBeDisabled();
|
||||
} else {
|
||||
test.skip();
|
||||
}
|
||||
});
|
||||
|
||||
test('应显示删除确认对话框', async ({ page }) => {
|
||||
const deleteBtns = page.locator('.t-table__body button:has-text("删除")');
|
||||
const count = await deleteBtns.count();
|
||||
|
||||
if (count > 0) {
|
||||
await deleteBtns.first().click();
|
||||
await expect(page.getByText('确定要删除这个供应商吗?')).toBeVisible();
|
||||
|
||||
// TDesign Popconfirm 取消按钮
|
||||
await page.locator('.t-popconfirm').getByRole('button', { name: '取消' }).click();
|
||||
} else {
|
||||
test.skip();
|
||||
}
|
||||
});
|
||||
});
|
||||
await expect(page.locator('.t-table__body')).toContainText('***stuv')
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user