# 质量改进迭代实施计划 > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. **Goal:** 根据系统评估报告,按优先级完成代码质量、测试框架和文档的改进工作,提升项目整体质量。 **Architecture:** 采用渐进式改进策略,优先解决高优先级问题(统一实现、测试覆盖率、报告可视化),然后推进中优先级改进(API文档、版本控制、性能监控),最后优化低优先级任务。 **Tech Stack:** Next.js 16, TypeScript, Jest, Playwright, Allure, OpenAPI/Swagger, Lighthouse CI --- ## 高优先级任务(1周内完成) ### Task 1: 统一联系表单实现 **问题:** 当前联系表单存在双重实现(Server Actions和API Route),需要统一为Server Actions。 **Files:** - Delete: `src/app/api/contact/route.ts` - Modify: `src/app/(marketing)/contact/page.tsx` - Modify: `src/app/(marketing)/contact/actions.ts` - Test: `src/app/api/contact/route.test.ts` (需要删除或迁移) **Step 1: 分析现有实现** 检查两个文件的实现差异: ```bash # 查看Server Actions实现 cat src/app/\(marketing\)/contact/actions.ts # 查看API Route实现 cat src/app/api/contact/route.ts ``` **Step 2: 增强Server Actions实现** 修改 `src/app/(marketing)/contact/actions.ts`,添加完整的验证和邮件发送逻辑: ```typescript 'use server'; import { Resend } from 'resend'; import { z } from 'zod'; const resend = new Resend(process.env.RESEND_API_KEY); const companyEmail = process.env.COMPANY_EMAIL || 'contact@novalon.cn'; const contactFormSchema = z.object({ name: z.string().min(1, '请填写姓名'), email: z.string().email('请输入有效的邮箱地址'), phone: z.string().optional(), subject: z.string().min(1, '请填写主题'), message: z.string().min(1, '请填写消息'), website: z.string().optional(), // 蜜罐字段 submitTime: z.string().optional(), mathHash: z.string().optional(), mathTimestamp: z.string().optional(), mathAnswer: z.string().optional(), }); export interface ContactFormState { success: boolean; message?: string; error?: string; } export async function submitContactForm( _prevState: ContactFormState | null, formData: FormData ): Promise { try { // 提取表单数据 const data = { name: formData.get('name') as string, email: formData.get('email') as string, phone: formData.get('phone') as string, subject: formData.get('subject') as string, message: formData.get('message') as string, website: formData.get('website') as string, submitTime: formData.get('submitTime') as string, mathHash: formData.get('mathHash') as string, mathTimestamp: formData.get('mathTimestamp') as string, mathAnswer: formData.get('mathAnswer') as string, }; // 验证数据 const validatedData = contactFormSchema.parse(data); // 蜜罐字段检查 if (validatedData.website) { console.log('Honeypot field filled, rejecting request'); return { success: true, message: '消息已发送' }; } // 时间检查(防止机器人快速提交) if (validatedData.submitTime) { const timeDiff = Date.now() - parseInt(validatedData.submitTime); if (timeDiff < 2000) { console.log('Submission too fast:', timeDiff); return { success: false, error: '提交过快,请稍后再试' }; } } // 数学验证码检查 if (validatedData.mathHash && validatedData.mathTimestamp && validatedData.mathAnswer !== undefined) { const expectedHash = btoa(`${validatedData.mathAnswer}-${validatedData.mathTimestamp}`); if (expectedHash !== validatedData.mathHash) { console.log('Invalid math captcha'); return { success: false, error: '验证码错误,请重新计算' }; } } // 发送邮件 const emailContent = generateEmailContent(validatedData); const { error } = await resend.emails.send({ from: '睿新致远官网 ', to: [companyEmail], subject: `📧 ${validatedData.subject} - ${validatedData.name}`, html: emailContent, replyTo: validatedData.email, }); if (error) { console.error('Resend API error:', error); return { success: false, error: '邮件发送失败,请稍后重试' }; } console.log('Email sent successfully'); return { success: true, message: '消息已发送' }; } catch (error) { console.error('Contact form submission error:', error); if (error instanceof z.ZodError) { return { success: false, error: error.errors[0].message }; } return { success: false, error: '提交失败,请重试' }; } } function generateEmailContent(data: z.infer): string { return `

📬 新的客户咨询

来自 睿新致远官方网站

姓名
${data.name}
邮箱
${data.phone ? `
电话
${data.phone}
` : ''}
主题
${data.subject}
咨询内容
${data.message}
`; } ``` **Step 3: 更新前端表单调用** 修改 `src/app/(marketing)/contact/page.tsx`,确保使用Server Actions: ```typescript 'use client'; import { useFormState, useFormStatus } from 'react-dom'; import { submitContactForm, type ContactFormState } from './actions'; function SubmitButton() { const { pending } = useFormStatus(); return ( ); } export default function ContactPage() { const [state, formAction] = useFormState(submitContactForm, null); return (
{/* 表单字段 */}
{/* 其他字段... */} {state?.error && (
{state.error}
)} {state?.success && (
{state.message}
)} ); } ``` **Step 4: 删除API Route文件** ```bash rm src/app/api/contact/route.ts rm src/app/api/contact/route.test.ts ``` **Step 5: 更新测试** 创建新的测试文件 `src/app/(marketing)/contact/actions.test.ts`: ```typescript import { submitContactForm } from './actions'; describe('submitContactForm', () => { it('should validate required fields', async () => { const formData = new FormData(); formData.append('name', ''); formData.append('email', 'invalid-email'); formData.append('subject', ''); formData.append('message', ''); const result = await submitContactForm(null, formData); expect(result.success).toBe(false); expect(result.error).toBeDefined(); }); it('should reject honeypot field', async () => { const formData = new FormData(); formData.append('name', 'Test'); formData.append('email', 'test@example.com'); formData.append('subject', 'Test Subject'); formData.append('message', 'Test Message'); formData.append('website', 'bot'); const result = await submitContactForm(null, formData); expect(result.success).toBe(true); expect(result.message).toBe('消息已发送'); }); it('should reject fast submission', async () => { const formData = new FormData(); formData.append('name', 'Test'); formData.append('email', 'test@example.com'); formData.append('subject', 'Test Subject'); formData.append('message', 'Test Message'); formData.append('submitTime', (Date.now() - 1000).toString()); const result = await submitContactForm(null, formData); expect(result.success).toBe(false); expect(result.error).toContain('提交过快'); }); }); ``` **Step 6: 运行测试验证** ```bash npm run test:unit ``` Expected: 所有测试通过 **Step 7: 手动测试** ```bash npm run dev # 访问 http://localhost:3000/contact # 填写表单并提交 # 验证邮件发送成功 ``` **Step 8: 提交更改** ```bash git add src/app/\(marketing\)/contact/ git add src/app/api/contact/ git commit -m "refactor: unify contact form implementation to use Server Actions - Remove duplicate API Route implementation - Enhance Server Actions with full validation and email sending - Add comprehensive tests for form validation - Improve error handling and user feedback BREAKING CHANGE: API endpoint /api/contact removed, use Server Actions instead" ``` --- ### Task 2: 配置单元测试覆盖率报告 **问题:** 缺少单元测试覆盖率报告,无法量化测试质量。 **Files:** - Modify: `jest.config.js` 或创建 `jest.config.ts` - Modify: `package.json` - Create: `.github/workflows/coverage.yml` (可选) **Step 1: 安装依赖** ```bash npm install --save-dev @types/jest jest ts-jest ``` **Step 2: 创建Jest配置文件** 创建 `jest.config.ts`: ```typescript import type { Config } from 'jest'; import nextJest from 'next/jest'; const createJestConfig = nextJest({ dir: './', }); const config: Config = { coverageProvider: 'v8', testEnvironment: 'jsdom', setupFilesAfterEnv: ['/jest.setup.ts'], moduleNameMapper: { '^@/(.*)$': '/src/$1', }, collectCoverage: true, coverageThreshold: { global: { branches: 80, functions: 80, lines: 80, statements: 80, }, }, coverageReporters: ['text', 'lcov', 'html', 'json-summary'], coverageDirectory: 'coverage', testMatch: [ '**/__tests__/**/*.[jt]s?(x)', '**/?(*.)+(spec|test).[jt]s?(x)', ], testPathIgnorePatterns: [ '/node_modules/', '/.next/', '/e2e/', '/dist/', ], collectCoverageFrom: [ 'src/**/*.{js,jsx,ts,tsx}', '!src/**/*.d.ts', '!src/**/*.stories.{js,jsx,ts,tsx}', '!src/**/__tests__/**', '!src/**/node_modules/**', ], }; export default createJestConfig(config); ``` **Step 3: 创建Jest Setup文件** 创建 `jest.setup.ts`: ```typescript import '@testing-library/jest-dom'; // Mock Next.js modules jest.mock('next/navigation', () => ({ useRouter() { return { push: jest.fn(), replace: jest.fn(), prefetch: jest.fn(), back: jest.fn(), pathname: '/', query: {}, asPath: '/', }; }, usePathname() { return '/'; }, useSearchParams() { return new URLSearchParams(); }, })); // Mock environment variables process.env.NEXTAUTH_SECRET = 'test-secret'; process.env.NEXTAUTH_URL = 'http://localhost:3000'; process.env.DATABASE_URL = 'file:./test.db'; process.env.RESEND_API_KEY = 'test-key'; process.env.COMPANY_EMAIL = 'test@example.com'; ``` **Step 4: 更新package.json脚本** 在 `package.json` 中添加: ```json { "scripts": { "test:unit": "jest", "test:unit:watch": "jest --watch", "test:unit:coverage": "jest --coverage", "test:coverage:open": "open coverage/lcov-report/index.html" } } ``` **Step 5: 运行覆盖率测试** ```bash npm run test:unit:coverage ``` Expected: 生成覆盖率报告,显示覆盖率百分比 **Step 6: 查看覆盖率报告** ```bash npm run test:coverage:open ``` Expected: 在浏览器中打开HTML覆盖率报告 **Step 7: 添加覆盖率徽章(可选)** 在 `README.md` 中添加: ```markdown [![Coverage Status](https://codecov.io/gh/your-org/your-repo/branch/main/graph/badge.svg)](https://codecov.io/gh/your-org/your-repo) ``` **Step 8: 提交更改** ```bash git add jest.config.ts jest.setup.ts package.json README.md git commit -m "feat: add unit test coverage reporting - Configure Jest with 80% coverage threshold - Add coverage reporters (text, lcov, html, json) - Create Jest setup with Next.js mocks - Add npm scripts for coverage reporting - Add coverage badge to README Target coverage: 80% for branches, functions, lines, statements" ``` --- ### Task 3: 配置Allure测试报告 **问题:** 缺少测试报告可视化,难以追踪测试历史和趋势。 **Files:** - Modify: `e2e/playwright.config.ts` - Modify: `package.json` - Create: `scripts/generate-allure-report.sh` **Step 1: 安装Allure依赖** ```bash npm install --save-dev allure-playwright ``` **Step 2: 更新Playwright配置** 修改 `e2e/playwright.config.ts`,确保Allure reporter已配置: ```typescript import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ testDir: './src/tests', reporter: [ ['html', { open: 'never' }], ['json', { outputFile: 'test-results/results.json' }], ['junit', { outputFile: 'test-results/junit.xml' }], ['allure-playwright', { outputFolder: 'allure-results', detail: true, suiteTitle: false, }], ], // ... 其他配置 }); ``` **Step 3: 创建报告生成脚本** 创建 `scripts/generate-allure-report.sh`: ```bash #!/bin/bash # 生成Allure报告 echo "Generating Allure report..." # 检查allure-results目录是否存在 if [ ! -d "allure-results" ]; then echo "Error: allure-results directory not found" echo "Please run tests first: npm run test" exit 1 fi # 生成报告 allure generate allure-results --clean -o allure-report echo "Allure report generated successfully!" echo "Opening report..." # 打开报告 allure open allure-report ``` **Step 4: 更新package.json脚本** 在 `package.json` 中添加: ```json { "scripts": { "test:report": "allure generate allure-results --clean -o allure-report && allure open allure-report", "test:report:ci": "allure generate allure-results --clean -o allure-report" } } ``` **Step 5: 运行测试生成报告** ```bash cd e2e npm test cd .. npm run test:report ``` Expected: - 测试执行完成 - Allure报告在浏览器中打开 - 显示测试统计、趋势、详情 **Step 6: 添加CI集成(可选)** 创建 `.github/workflows/test-report.yml`: ```yaml name: Test Report on: push: branches: [main, develop] pull_request: branches: [main, develop] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: '18' cache: 'npm' - name: Install dependencies run: npm ci - name: Run E2E tests run: npm run test:e2e - name: Generate Allure report if: always() run: npm run test:report:ci - name: Upload Allure report if: always() uses: actions/upload-artifact@v3 with: name: allure-report path: allure-report/ retention-days: 30 ``` **Step 7: 提交更改** ```bash git add e2e/playwright.config.ts package.json scripts/generate-allure-report.sh .github/workflows/test-report.yml git commit -m "feat: add Allure test report visualization - Configure Allure reporter in Playwright - Add report generation scripts - Add CI integration for automatic report generation - Add npm scripts for easy report access Allure report provides: - Test statistics and trends - Detailed test execution history - Visual test results dashboard" ``` --- ## 中优先级任务(2周内完成) ### Task 4: 引入OpenAPI文档 **问题:** 缺少API文档,不利于前后端协作和API维护。 **Files:** - Create: `src/app/api/docs/route.ts` - Create: `src/lib/openapi.ts` - Modify: `package.json` **Step 1: 安装依赖** ```bash npm install swagger-jsdoc swagger-ui-react npm install --save-dev @types/swagger-jsdoc ``` **Step 2: 创建OpenAPI配置** 创建 `src/lib/openapi.ts`: ```typescript import swaggerJsdoc from 'swagger-jspec'; const options: swaggerJsdoc.Options = { definition: { openapi: '3.0.0', info: { title: 'Novalon Website API', version: '1.0.0', description: '四川睿新致远科技有限公司官方网站API文档', contact: { name: '睿新致远', email: 'contact@novalon.cn', url: 'https://novalon.cn', }, }, servers: [ { url: 'http://localhost:3000/api', description: '开发环境', }, { url: 'https://novalon.cn/api', description: '生产环境', }, ], components: { securitySchemes: { bearerAuth: { type: 'http', scheme: 'bearer', bearerFormat: 'JWT', }, }, schemas: { User: { type: 'object', properties: { id: { type: 'string' }, email: { type: 'string', format: 'email' }, name: { type: 'string' }, isAdmin: { type: 'boolean' }, createdAt: { type: 'string', format: 'date-time' }, }, }, Content: { type: 'object', properties: { id: { type: 'string' }, type: { type: 'string', enum: ['news', 'product', 'service', 'case'] }, title: { type: 'string' }, slug: { type: 'string' }, excerpt: { type: 'string' }, content: { type: 'string' }, status: { type: 'string', enum: ['draft', 'published', 'archived'] }, createdAt: { type: 'string', format: 'date-time' }, }, }, Error: { type: 'object', properties: { success: { type: 'boolean', example: false }, error: { type: 'string' }, }, }, }, }, }, apis: ['./src/app/api/**/*.ts'], // 指向API路由文件 }; export const specs = swaggerJsdoc(options); ``` **Step 3: 创建API文档路由** 创建 `src/app/api/docs/route.ts`: ```typescript import { NextResponse } from 'next/server'; import { specs } from '@/lib/openapi'; export async function GET() { return NextResponse.json(specs); } ``` **Step 4: 创建Swagger UI页面** 创建 `src/app/api-docs/page.tsx`: ```typescript 'use client'; import SwaggerUI from 'swagger-ui-react'; import 'swagger-ui-react/swagger-ui.css'; export default function ApiDocsPage() { return (
); } ``` **Step 5: 为API添加JSDoc注释** 修改 `src/app/api/admin/content/route.ts`: ```typescript /** * @swagger * /admin/content: * get: * summary: 获取内容列表 * tags: [Content] * security: * - bearerAuth: [] * parameters: * - in: query * name: type * schema: * type: string * enum: [news, product, service, case] * - in: query * name: status * schema: * type: string * enum: [draft, published, archived] * - in: query * name: page * schema: * type: integer * default: 1 * - in: query * name: limit * schema: * type: integer * default: 20 * responses: * 200: * description: 成功获取内容列表 * content: * application/json: * schema: * type: object * properties: * success: * type: boolean * data: * type: object * properties: * items: * type: array * items: * $ref: '#/components/schemas/Content' * pagination: * type: object * 401: * description: 未授权 * content: * application/json: * schema: * $ref: '#/components/schemas/Error' */ export async function GET(request: NextRequest) { // ... 现有实现 } /** * @swagger * /admin/content: * post: * summary: 创建新内容 * tags: [Content] * security: * - bearerAuth: [] * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - type * - title * - slug * properties: * type: * type: string * enum: [news, product, service, case] * title: * type: string * slug: * type: string * excerpt: * type: string * contentBody: * type: string * status: * type: string * enum: [draft, published] * responses: * 201: * description: 内容创建成功 * content: * application/json: * schema: * $ref: '#/components/schemas/Content' * 400: * description: 请求参数错误 * 401: * description: 未授权 */ export async function POST(request: NextRequest) { // ... 现有实现 } ``` **Step 6: 更新package.json脚本** ```json { "scripts": { "docs:api": "next dev -p 3000", "docs:generate": "ts-node scripts/generate-api-docs.ts" } } ``` **Step 7: 测试API文档** ```bash npm run dev # 访问 http://localhost:3000/api-docs ``` Expected: - Swagger UI界面正常显示 - 所有API端点都有文档 - 可以在线测试API **Step 8: 提交更改** ```bash git add src/lib/openapi.ts src/app/api/docs/ src/app/api-docs/ src/app/api/admin/content/route.ts package.json git commit -m "feat: add OpenAPI/Swagger documentation - Create OpenAPI specification configuration - Add Swagger UI page for API documentation - Add JSDoc annotations to API routes - Add npm scripts for documentation access API documentation available at /api-docs Provides interactive API testing interface" ``` --- ### Task 5: 引入API版本控制 **问题:** API没有版本控制,不利于未来升级和维护。 **Files:** - Create: `src/app/api/v1/` 目录结构 - Modify: 所有API路由文件 - Update: 前端API调用 **Step 1: 创建版本化目录结构** ```bash mkdir -p src/app/api/v1/admin mkdir -p src/app/api/v1/auth mkdir -p src/app/api/v1/content mkdir -p src/app/api/v1/health ``` **Step 2: 迁移API路由** 将现有API文件移动到v1目录: ```bash # 迁移管理后台API mv src/app/api/admin/* src/app/api/v1/admin/ # 迁移认证API mv src/app/api/auth/* src/app/api/v1/auth/ # 迁移内容API mv src/app/api/content/* src/app/api/v1/content/ # 迁移健康检查API mv src/app/api/health/* src/app/api/v1/health/ ``` **Step 3: 创建API版本路由** 创建 `src/app/api/v1/route.ts`: ```typescript import { NextResponse } from 'next/server'; export async function GET() { return NextResponse.json({ version: 'v1', endpoints: { admin: '/api/v1/admin', auth: '/api/v1/auth', content: '/api/v1/content', health: '/api/v1/health', }, }); } ``` **Step 4: 创建默认API路由(向后兼容)** 修改 `src/app/api/route.ts`: ```typescript import { NextResponse } from 'next/server'; export async function GET() { return NextResponse.json({ message: 'Novalon Website API', currentVersion: 'v1', documentation: '/api-docs', versions: { v1: '/api/v1', }, }); } ``` **Step 5: 更新前端API调用** 修改 `src/lib/api/client.ts`: ```typescript const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || '/api/v1'; export async function fetchApi(endpoint: string, options?: RequestInit): Promise { const url = `${API_BASE_URL}${endpoint}`; const response = await fetch(url, { ...options, headers: { 'Content-Type': 'application/json', ...options?.headers, }, }); if (!response.ok) { throw new Error(`API Error: ${response.statusText}`); } return response.json(); } ``` **Step 6: 更新所有API调用** 搜索并替换所有API调用: ```bash # 查找所有API调用 grep -r "/api/admin" src/ grep -r "/api/auth" src/ grep -r "/api/content" src/ # 替换为版本化API # 例如:/api/admin/content -> /api/v1/admin/content ``` **Step 7: 更新测试** 修改所有测试文件中的API路径: ```typescript // 旧路径 await page.goto('/api/admin/content'); // 新路径 await page.goto('/api/v1/admin/content'); ``` **Step 8: 运行测试验证** ```bash npm run test:unit npm run test:e2e ``` Expected: 所有测试通过 **Step 9: 提交更改** ```bash git add src/app/api/ git add src/lib/api/ git add e2e/ git commit -m "feat: add API version control (v1) - Create versioned API structure (/api/v1/*) - Migrate all API routes to v1 - Update frontend API client to use versioned endpoints - Update all tests to use new API paths - Add backward compatibility for root API endpoint BREAKING CHANGE: All API endpoints now require /api/v1 prefix Migration guide: Replace /api/* with /api/v1/*" ``` --- ### Task 6: 集成Lighthouse CI **问题:** 缺少端到端性能监控,无法持续追踪性能指标。 **Files:** - Create: `.lighthouserc.json` - Create: `.github/workflows/lighthouse.yml` - Modify: `package.json` **Step 1: 安装Lighthouse CI** ```bash npm install --save-dev @lhci/cli@0.10.x ``` **Step 2: 创建Lighthouse CI配置** 创建 `.lighthouserc.json`: ```json { "ci": { "collect": { "numberOfRuns": 3, "settings": { "preset": "desktop", "throttling": { "rttMs": 40, "throughputKbps": 10240, "cpuSlowdownMultiplier": 1 } }, "url": [ "http://localhost:3000/", "http://localhost:3000/about", "http://localhost:3000/products", "http://localhost:3000/services", "http://localhost:3000/cases", "http://localhost:3000/news", "http://localhost:3000/contact" ] }, "assert": { "assertions": { "categories:performance": ["error", { "minScore": 0.9 }], "categories:accessibility": ["error", { "minScore": 0.9 }], "categories:best-practices": ["error", { "minScore": 0.9 }], "categories:seo": ["error", { "minScore": 0.9 }], "first-contentful-paint": ["error", { "maxNumericValue": 2000 }], "largest-contentful-paint": ["error", { "maxNumericValue": 3000 }], "cumulative-layout-shift": ["error", { "maxNumericValue": 0.1 }], "total-blocking-time": ["error", { "maxNumericValue": 300 }] } }, "upload": { "target": "temporary-public-storage" } } } ``` **Step 3: 创建CI工作流** 创建 `.github/workflows/lighthouse.yml`: ```yaml name: Lighthouse CI on: push: branches: [main, develop] pull_request: branches: [main, develop] jobs: lighthouse: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: '18' cache: 'npm' - name: Install dependencies run: npm ci - name: Build application run: npm run build - name: Start application run: npm start & env: PORT: 3000 - name: Wait for application run: npx wait-on http://localhost:3000 - name: Run Lighthouse CI run: npx lhci autorun - name: Upload Lighthouse results uses: actions/upload-artifact@v3 with: name: lighthouse-results path: .lighthouseci/ retention-days: 30 ``` **Step 4: 更新package.json脚本** ```json { "scripts": { "lighthouse": "lhci autorun", "lighthouse:collect": "lhci collect", "lighthouse:assert": "lhci assert", "lighthouse:upload": "lhci upload" } } ``` **Step 5: 本地测试** ```bash # 启动应用 npm run build npm start & # 运行Lighthouse CI npm run lighthouse ``` Expected: - 生成性能报告 - 所有断言通过 - 报告保存在 `.lighthouseci/` 目录 **Step 6: 查看报告** ```bash # 打开最新的报告 open .lighthouseci/lhr-*.html ``` **Step 7: 提交更改** ```bash git add .lighthouserc.json .github/workflows/lighthouse.yml package.json git commit -m "feat: integrate Lighthouse CI for performance monitoring - Add Lighthouse CI configuration - Add CI workflow for automated performance testing - Set performance budgets (90% score minimum) - Add Core Web Vitals thresholds - Add npm scripts for local performance testing Performance targets: - Performance score: ≥90% - Accessibility score: ≥90% - Best practices score: ≥90% - SEO score: ≥90% - LCP: ≤3000ms - FCP: ≤2000ms - CLS: ≤0.1 - TBT: ≤300ms" ``` --- ## 低优先级任务(1个月内完成) ### Task 7: 引入API契约测试 **问题:** 缺少API契约测试,无法确保API响应符合预期格式。 **Files:** - Create: `tests/api-contracts/` - Modify: `package.json` **Step 1: 安装依赖** ```bash npm install --save-dev jest-openapi ``` **Step 2: 创建契约测试配置** 创建 `tests/api-contracts/setup.ts`: ```typescript import { matchers } from 'jest-openapi'; import { specs } from '@/lib/openapi'; expect.extend(matchers(specs)); ``` **Step 3: 创建契约测试** 创建 `tests/api-contracts/content.api.test.ts`: ```typescript import { fetchApi } from '@/lib/api/client'; describe('Content API Contract Tests', () => { it('GET /api/v1/admin/content should match schema', async () => { const response = await fetchApi('/admin/content'); expect(response).toSatisfySchemaInApiSpec('Content'); }); it('POST /api/v1/admin/content should match schema', async () => { const newContent = { type: 'news', title: 'Test News', slug: 'test-news', contentBody: 'Test content', }; const response = await fetchApi('/admin/content', { method: 'POST', body: JSON.stringify(newContent), }); expect(response).toSatisfySchemaInApiSpec('Content'); }); }); ``` **Step 4: 运行契约测试** ```bash npm run test:api-contracts ``` **Step 5: 提交更改** ```bash git add tests/api-contracts/ package.json git commit -m "feat: add API contract testing - Add jest-openapi for schema validation - Create contract tests for all API endpoints - Ensure API responses match OpenAPI schema Contract tests validate: - Response structure matches schema - Required fields are present - Data types are correct" ``` --- ### Task 8: 优化测试执行时间 **问题:** 测试执行时间可能过长,需要优化以提高效率。 **Files:** - Modify: `e2e/playwright.config.ts` - Create: `scripts/analyze-test-performance.ts` **Step 1: 分析慢速测试** 创建 `scripts/analyze-test-performance.ts`: ```typescript import { execSync } from 'child_process'; import * as fs from 'fs'; interface TestResult { file: string; duration: number; status: 'passed' | 'failed'; } function analyzeTestPerformance() { console.log('Analyzing test performance...\n'); // 运行测试并收集性能数据 const result = execSync('npx playwright test --reporter=json', { encoding: 'utf-8', cwd: 'e2e', }); const testResults: TestResult[] = JSON.parse(result); // 按执行时间排序 const sortedResults = testResults.sort((a, b) => b.duration - a.duration); // 输出最慢的10个测试 console.log('Top 10 slowest tests:\n'); sortedResults.slice(0, 10).forEach((test, index) => { console.log(`${index + 1}. ${test.file}`); console.log(` Duration: ${(test.duration / 1000).toFixed(2)}s`); console.log(` Status: ${test.status}\n`); }); // 生成优化建议 const slowTests = sortedResults.filter(t => t.duration > 5000); if (slowTests.length > 0) { console.log('\nOptimization recommendations:\n'); slowTests.forEach(test => { console.log(`- ${test.file}: Consider splitting or optimizing`); }); } // 保存报告 fs.writeFileSync( 'test-performance-report.json', JSON.stringify(sortedResults, null, 2) ); console.log('\nReport saved to test-performance-report.json'); } analyzeTestPerformance(); ``` **Step 2: 运行性能分析** ```bash ts-node scripts/analyze-test-performance.ts ``` **Step 3: 优化慢速测试** 根据分析结果优化测试: 1. **减少等待时间**: ```typescript // 不推荐 await page.waitForTimeout(5000); // 推荐 await page.waitForSelector('[data-testid="result"]'); ``` 2. **并行执行**: ```typescript // playwright.config.ts { fullyParallel: true, workers: '75%', } ``` 3. **拆分大测试**: ```typescript // 将一个大测试拆分为多个小测试 test.describe('User Registration', () => { test('should fill registration form', async ({ page }) => { // 只测试表单填写 }); test('should submit registration', async ({ page }) => { // 只测试提交 }); }); ``` **Step 4: 提交更改** ```bash git add scripts/analyze-test-performance.ts e2e/playwright.config.ts git commit -m "perf: optimize test execution time - Add test performance analysis script - Identify and optimize slow tests - Enable parallel execution - Reduce unnecessary waits Expected improvement: 20-30% faster test execution" ``` --- ## 执行计划总结 ### 高优先级任务(1周内) - ✅ Task 1: 统一联系表单实现 - ✅ Task 2: 配置单元测试覆盖率报告 - ✅ Task 3: 配置Allure测试报告 ### 中优先级任务(2周内) - ✅ Task 4: 引入OpenAPI文档 - ✅ Task 5: 引入API版本控制 - ✅ Task 6: 集成Lighthouse CI ### 低优先级任务(1个月内) - ✅ Task 7: 引入API契约测试 - ✅ Task 8: 优化测试执行时间 --- ## 验收标准 ### 功能验收 - [ ] 所有改进任务完成 - [ ] 所有测试通过 - [ ] 文档更新完整 ### 质量验收 - [ ] 单元测试覆盖率 ≥ 80% - [ ] E2E测试通过率 ≥ 95% - [ ] 性能评分 ≥ 90% - [ ] 可访问性评分 ≥ 90% ### 文档验收 - [ ] API文档完整 - [ ] README更新 - [ ] 迁移指南编写 --- **计划创建时间**: 2026-03-20 **预计完成时间**: 2026-04-20 **负责人**: 张翔 **状态**: 待执行