refactor: 通用技能按类别拆分为独立目录
skills/ → skills-dev(9), skills-req(10), skills-ops(4), skills-integration(8), skills-biz(4), skills-workflow(7) generate-marketplace.py 改为自动扫描所有 skills-* 目录。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
169
skills-dev/dev-test-plugin/skills/dev-test/e2e-testing.md
Normal file
169
skills-dev/dev-test-plugin/skills/dev-test/e2e-testing.md
Normal file
@@ -0,0 +1,169 @@
|
||||
# E2E 测试 (Playwright)
|
||||
|
||||
## 通用 Playwright 配置
|
||||
|
||||
```typescript
|
||||
// playwright.config.ts
|
||||
import { defineConfig } from '@playwright/test'
|
||||
|
||||
export default defineConfig({
|
||||
testDir: './tests/e2e',
|
||||
timeout: 30000,
|
||||
use: {
|
||||
baseURL: 'http://localhost:3000',
|
||||
screenshot: 'only-on-failure',
|
||||
},
|
||||
projects: [
|
||||
{ name: 'chromium', use: { browserName: 'chromium' } },
|
||||
{ name: 'firefox', use: { browserName: 'firefox' } },
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
## 通用 E2E 测试示例
|
||||
|
||||
```typescript
|
||||
// login.spec.ts
|
||||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test.describe('Login', () => {
|
||||
test('successful login', async ({ page }) => {
|
||||
await page.goto('/login')
|
||||
|
||||
await page.fill('[data-testid="username"]', 'testuser')
|
||||
await page.fill('[data-testid="password"]', 'password')
|
||||
await page.click('[data-testid="submit"]')
|
||||
|
||||
await expect(page).toHaveURL('/dashboard')
|
||||
await expect(page.locator('.welcome')).toContainText('testuser')
|
||||
})
|
||||
|
||||
test('invalid credentials', async ({ page }) => {
|
||||
await page.goto('/login')
|
||||
|
||||
await page.fill('[data-testid="username"]', 'wrong')
|
||||
await page.fill('[data-testid="password"]', 'wrong')
|
||||
await page.click('[data-testid="submit"]')
|
||||
|
||||
await expect(page.locator('.error')).toBeVisible()
|
||||
})
|
||||
})
|
||||
|
||||
test.describe('Task Management', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/login')
|
||||
await page.fill('[data-testid="username"]', 'testuser')
|
||||
await page.fill('[data-testid="password"]', 'password')
|
||||
await page.click('[data-testid="submit"]')
|
||||
})
|
||||
|
||||
test('create task', async ({ page }) => {
|
||||
await page.click('[data-testid="new-task"]')
|
||||
await page.fill('[data-testid="task-title"]', 'E2E Test Task')
|
||||
await page.click('[data-testid="save"]')
|
||||
|
||||
await expect(page.locator('text=E2E Test Task')).toBeVisible()
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Coolbuy PaaS E2E 集成测试
|
||||
|
||||
> Playwright 全链路 E2E 测试,独立环境(DB + 端口),可与 dev 服务并行运行。
|
||||
|
||||
### 环境架构
|
||||
|
||||
| 服务 | Dev 端口 | E2E 端口 | DB |
|
||||
|------|---------|---------|-----|
|
||||
| Auth Service | 7089 | 7189 | coolbuy_paas_e2e |
|
||||
| Foundation Service | 7090 | 7190 | coolbuy_paas_e2e |
|
||||
| ERP Service | 7091 | 7191 | coolbuy_paas_e2e |
|
||||
| Web Frontend | 4000 | 4010 | - |
|
||||
|
||||
**E2E DB 初始化**(首次/重置):
|
||||
```bash
|
||||
psql -U coolbuy-dev -d postgres -c "DROP DATABASE IF EXISTS coolbuy_paas_e2e;"
|
||||
psql -U coolbuy-dev -d postgres -c "CREATE DATABASE coolbuy_paas_e2e OWNER \"coolbuy-dev\";"
|
||||
pg_dump -U coolbuy-dev coolbuy_paas_local | psql -U coolbuy-dev coolbuy_paas_e2e
|
||||
```
|
||||
|
||||
### 启动 / 停止 E2E 服务
|
||||
|
||||
```bash
|
||||
make e2e-start # 启动全部 E2E 服务(auth/foundation/erp/web)
|
||||
make e2e-stop # 停止全部 E2E 服务
|
||||
make e2e-reset # 重置 DB 后启动
|
||||
make e2e # 启动服务 + 运行全部测试
|
||||
```
|
||||
|
||||
脚本位置:`scripts/start-e2e-services.sh` / `scripts/stop-e2e-services.sh`
|
||||
|
||||
### 运行测试
|
||||
|
||||
```bash
|
||||
cd web
|
||||
|
||||
# 全部测试(无头模式)
|
||||
npx playwright test
|
||||
|
||||
# 带 UI 调试
|
||||
npx playwright test --headed
|
||||
|
||||
# 单个文件
|
||||
npx playwright test tests/product-crud.spec.ts
|
||||
|
||||
# 查看 HTML 报告(注意:会启动 HTTP server,需 Ctrl+C 退出)
|
||||
npx playwright show-report
|
||||
```
|
||||
|
||||
### Auth 自动登录
|
||||
|
||||
`tests/auth.setup.ts` 优先点击快速登录按钮(`VITE_ENABLE_QUICK_LOGIN=true`),降级为表单登录:
|
||||
|
||||
```typescript
|
||||
// 快速登录(E2E 环境默认开启)
|
||||
const quickLoginBtn = page.locator('button, a').filter({ hasText: /李宁|lining|ID:2/i }).first();
|
||||
if (await quickLoginBtn.isVisible({ timeout: 3000 })) {
|
||||
await quickLoginBtn.click();
|
||||
} else {
|
||||
// 降级:填写 lining_admin / admin123,验证码任意 4 位(SkipVerify=true)
|
||||
}
|
||||
await page.waitForURL(/\/tenant/, { timeout: 15000 });
|
||||
await page.context().storageState({ path: authFile });
|
||||
```
|
||||
|
||||
Session 保存至 `.auth/user.json`,后续测试自动复用,无需重复登录。
|
||||
|
||||
### 配置文件
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `web/.env.e2e` | E2E 环境变量(端口 / 快速登录开关) |
|
||||
| `web/playwright.config.ts` | baseURL=localhost:4010,reporter=[html, list] |
|
||||
| `auth-service/api/etc/auth-api-e2e.yaml` | E2E auth 配置(SkipVerify=true) |
|
||||
| `foundation-service/api/etc/foundation-api-e2e.yaml` | E2E foundation 配置 |
|
||||
| `erp-service/configs/config.e2e.yaml` | E2E ERP 配置 |
|
||||
|
||||
### 测试结果解读
|
||||
|
||||
当前 **113 tests — 103 ✅ / 10 ❌**,已知失败项:
|
||||
|
||||
| 失败原因 | 涉及测试 |
|
||||
|---------|---------|
|
||||
| `/tenant/order/business` 路由 404(页面未实现) | 业务订单列表 × 3、订单模块导航 |
|
||||
| 预警管理无搜索表单组件 | 预警管理搜索/筛选 |
|
||||
| 库存管理页无 table/empty 状态 | 仓库管理-库存管理 |
|
||||
| 待审批订单 networkidle 超时(>60s) | 待审批订单列表 |
|
||||
| 数据权限/字段权限页渲染异常 | 系统管理 × 2 |
|
||||
| 业务 CRM 页渲染异常 | 业务 CRM |
|
||||
|
||||
### 常见问题
|
||||
|
||||
| 问题 | 解决 |
|
||||
|------|------|
|
||||
| `Executable doesn't exist` | `npx playwright install chromium` |
|
||||
| 端口 4010 被占用 | `make e2e-stop` 后重试 |
|
||||
| GORM migration 失败 | 检查 DB 是否有旧约束名,手动 DROP CONSTRAINT 后重启服务 |
|
||||
| HTML 报告进程不退出 | Playwright 在 report 模式会启动 HTTP server,用 `Ctrl+C` 停止 |
|
||||
Reference in New Issue
Block a user