5d5b7feb0a
添加Playwright测试框架配置和基础页面对象 实现冒烟测试用例覆盖首页和联系页面核心功能 更新导航组件以支持滚动高亮功能 添加BackButton组件统一返回按钮行为 配置Woodpecker CI集成和测试报告生成
886 lines
22 KiB
Markdown
886 lines
22 KiB
Markdown
# E2E测试结果驱动的系统优化实施计划
|
|
|
|
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
|
|
|
**目标:** 基于E2E测试结果,通过TDD方法系统性地修复测试失败问题,提升系统质量
|
|
|
|
**架构:** 采用测试驱动开发(TDD)方法,按照优先级逐步修复问题:优先级1(关键功能)→ 优先级2(性能优化)→ 优先级3(响应式改进)
|
|
|
|
**技术栈:** Next.js 15, React, TypeScript, Playwright E2E测试, Tailwind CSS
|
|
|
|
---
|
|
|
|
## 阶段1: 优先级1 - 关键功能修复
|
|
|
|
### Task 1: 完善联系表单提交功能
|
|
|
|
**背景:** 回归测试显示联系表单提交功能未完全实现,导致测试失败
|
|
|
|
**Files:**
|
|
- Create: `src/app/contact/actions.ts`
|
|
- Modify: `src/app/contact/page.tsx`
|
|
- Test: `e2e/src/tests/regression/contact-form.regression.spec.ts`
|
|
|
|
**Step 1: 编写失败的测试**
|
|
|
|
```typescript
|
|
// e2e/src/tests/regression/contact-form.regression.spec.ts
|
|
test('应该能够提交完整的表单', async ({ contactPage }) => {
|
|
await contactPage.fillContactForm({
|
|
name: '测试用户',
|
|
email: 'test@example.com',
|
|
phone: '13800138000',
|
|
message: '这是一条测试消息'
|
|
});
|
|
|
|
await contactPage.submitForm();
|
|
|
|
await contactPage.page.waitForTimeout(2000);
|
|
|
|
const successMessage = await contactPage.page.locator('text=提交成功').isVisible();
|
|
expect(successMessage).toBeTruthy();
|
|
});
|
|
```
|
|
|
|
**Step 2: 运行测试验证失败**
|
|
|
|
Run: `cd e2e && npm run test:regression -- --grep "应该能够提交完整的表单"`
|
|
|
|
Expected: FAIL - 表单提交功能未实现
|
|
|
|
**Step 3: 创建表单提交Action**
|
|
|
|
```typescript
|
|
// src/app/contact/actions.ts
|
|
'use server';
|
|
|
|
export async function submitContactForm(formData: FormData) {
|
|
const name = formData.get('name') as string;
|
|
const email = formData.get('email') as string;
|
|
const phone = formData.get('phone') as string;
|
|
const message = formData.get('message') as string;
|
|
|
|
if (!name || !email || !message) {
|
|
return { success: false, error: '请填写必填字段' };
|
|
}
|
|
|
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
if (!emailRegex.test(email)) {
|
|
return { success: false, error: '请输入有效的邮箱地址' };
|
|
}
|
|
|
|
return { success: true, message: '提交成功' };
|
|
}
|
|
```
|
|
|
|
**Step 4: 更新联系页面集成表单提交**
|
|
|
|
```typescript
|
|
// src/app/contact/page.tsx
|
|
'use client';
|
|
|
|
import { useState } from 'react';
|
|
import { submitContactForm } from './actions';
|
|
|
|
export default function ContactPage() {
|
|
const [formData, setFormData] = useState({
|
|
name: '',
|
|
email: '',
|
|
phone: '',
|
|
message: ''
|
|
});
|
|
const [submitResult, setSubmitResult] = useState<{ success: boolean; message?: string } | null>(null);
|
|
|
|
const handleSubmit = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
const formDataObj = new FormData();
|
|
Object.entries(formData).forEach(([key, value]) => {
|
|
formDataObj.append(key, value);
|
|
});
|
|
|
|
const result = await submitContactForm(formDataObj);
|
|
setSubmitResult(result);
|
|
};
|
|
|
|
return (
|
|
<form onSubmit={handleSubmit}>
|
|
{/* 表单字段 */}
|
|
{submitResult && (
|
|
<div className={submitResult.success ? 'text-green-600' : 'text-red-600'}>
|
|
{submitResult.message}
|
|
</div>
|
|
)}
|
|
</form>
|
|
);
|
|
}
|
|
```
|
|
|
|
**Step 5: 运行测试验证通过**
|
|
|
|
Run: `cd e2e && npm run test:regression -- --grep "应该能够提交完整的表单"`
|
|
|
|
Expected: PASS
|
|
|
|
**Step 6: 提交**
|
|
|
|
```bash
|
|
git add src/app/contact/actions.ts src/app/contact/page.tsx
|
|
git commit -m "feat: implement contact form submission with validation"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 2: 优化移动端菜单交互
|
|
|
|
**背景:** 回归测试显示移动端菜单交互需要完善
|
|
|
|
**Files:**
|
|
- Modify: `src/components/Header.tsx`
|
|
- Test: `e2e/src/tests/regression/navigation.regression.spec.ts`
|
|
|
|
**Step 1: 编写失败的测试**
|
|
|
|
```typescript
|
|
// e2e/src/tests/regression/navigation.regression.spec.ts
|
|
test('应该能够打开和关闭移动端菜单', async ({ homePage }) => {
|
|
await homePage.page.setViewportSize({ width: 375, height: 667 });
|
|
|
|
await homePage.openMobileMenu();
|
|
const isMenuOpen = await homePage.isMobileMenuOpen();
|
|
expect(isMenuOpen).toBeTruthy();
|
|
|
|
await homePage.closeMobileMenu();
|
|
const isMenuClosed = await !(await homePage.isMobileMenuOpen());
|
|
expect(isMenuClosed).toBeTruthy();
|
|
});
|
|
```
|
|
|
|
**Step 2: 运行测试验证失败**
|
|
|
|
Run: `cd e2e && npm run test:regression -- --grep "应该能够打开和关闭移动端菜单"`
|
|
|
|
Expected: FAIL - 移动端菜单交互未实现
|
|
|
|
**Step 3: 实现移动端菜单状态管理**
|
|
|
|
```typescript
|
|
// src/components/Header.tsx
|
|
'use client';
|
|
|
|
import { useState } from 'react';
|
|
|
|
export default function Header() {
|
|
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
|
|
|
const toggleMobileMenu = () => {
|
|
setIsMobileMenuOpen(!isMobileMenuOpen);
|
|
};
|
|
|
|
return (
|
|
<header>
|
|
<button
|
|
onClick={toggleMobileMenu}
|
|
aria-label={isMobileMenuOpen ? "关闭菜单" : "打开菜单"}
|
|
aria-expanded={isMobileMenuOpen}
|
|
>
|
|
<svg>...</svg>
|
|
</button>
|
|
|
|
<nav
|
|
id="mobile-menu-panel"
|
|
className={isMobileMenuOpen ? 'block' : 'hidden'}
|
|
aria-hidden={!isMobileMenuOpen}
|
|
>
|
|
{/* 菜单项 */}
|
|
</nav>
|
|
</header>
|
|
);
|
|
}
|
|
```
|
|
|
|
**Step 4: 运行测试验证通过**
|
|
|
|
Run: `cd e2e && npm run test:regression -- --grep "应该能够打开和关闭移动端菜单"`
|
|
|
|
Expected: PASS
|
|
|
|
**Step 5: 提交**
|
|
|
|
```bash
|
|
git add src/components/Header.tsx
|
|
git commit -m "feat: implement mobile menu toggle functionality"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 3: 修复页面滚动问题
|
|
|
|
**背景:** 回归测试显示页面滚动事件处理需要优化
|
|
|
|
**Files:**
|
|
- Create: `src/hooks/useSmoothScroll.ts`
|
|
- Modify: `src/components/Header.tsx`, `src/app/contact/page.tsx`
|
|
- Test: `e2e/src/tests/regression/navigation.regression.spec.ts`
|
|
|
|
**Step 1: 编写失败的测试**
|
|
|
|
```typescript
|
|
// e2e/src/tests/regression/navigation.regression.spec.ts
|
|
test('应该能够平滑滚动到锚点', async ({ homePage }) => {
|
|
await homePage.navigateTo('/');
|
|
|
|
await homePage.scrollToSection('services');
|
|
const servicesSection = homePage.page.locator('#services');
|
|
const isVisible = await servicesSection.isVisible();
|
|
expect(isVisible).toBeTruthy();
|
|
});
|
|
```
|
|
|
|
**Step 2: 运行测试验证失败**
|
|
|
|
Run: `cd e2e && npm run test:regression -- --grep "应该能够平滑滚动到锚点"`
|
|
|
|
Expected: FAIL - 平滑滚动未实现
|
|
|
|
**Step 3: 创建平滑滚动Hook**
|
|
|
|
```typescript
|
|
// src/hooks/useSmoothScroll.ts
|
|
import { useEffect } from 'react';
|
|
|
|
export function useSmoothScroll() {
|
|
useEffect(() => {
|
|
const handleAnchorClick = (e: MouseEvent) => {
|
|
const target = e.target as HTMLAnchorElement;
|
|
if (target.tagName === 'A' && target.hash) {
|
|
e.preventDefault();
|
|
const element = document.querySelector(target.hash);
|
|
if (element) {
|
|
element.scrollIntoView({ behavior: 'smooth' });
|
|
}
|
|
}
|
|
};
|
|
|
|
document.addEventListener('click', handleAnchorClick);
|
|
return () => document.removeEventListener('click', handleAnchorClick);
|
|
}, []);
|
|
}
|
|
```
|
|
|
|
**Step 4: 集成平滑滚动到页面**
|
|
|
|
```typescript
|
|
// src/app/contact/page.tsx
|
|
import { useSmoothScroll } from '@/hooks/useSmoothScroll';
|
|
|
|
export default function ContactPage() {
|
|
useSmoothScroll();
|
|
|
|
return (
|
|
<div>
|
|
<a href="#contact-form">联系我们</a>
|
|
<section id="contact-form">
|
|
{/* 表单 */}
|
|
</section>
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
|
|
**Step 5: 运行测试验证通过**
|
|
|
|
Run: `cd e2e && npm run test:regression -- --grep "应该能够平滑滚动到锚点"`
|
|
|
|
Expected: PASS
|
|
|
|
**Step 6: 提交**
|
|
|
|
```bash
|
|
git add src/hooks/useSmoothScroll.ts src/app/contact/page.tsx
|
|
git commit -m "feat: implement smooth scrolling for anchor links"
|
|
```
|
|
|
|
---
|
|
|
|
## 阶段2: 优先级2 - 性能优化
|
|
|
|
### Task 4: 优化页面加载时间
|
|
|
|
**背景:** 性能测试显示页面加载时间超出阈值
|
|
|
|
**Files:**
|
|
- Modify: `next.config.mjs`
|
|
- Create: `src/app/loading.tsx`
|
|
- Test: `e2e/src/tests/performance/performance.spec.ts`
|
|
|
|
**Step 1: 编写失败的测试**
|
|
|
|
```typescript
|
|
// e2e/src/tests/performance/performance.spec.ts
|
|
test('首页应该在2秒内完成加载', async ({ page }) => {
|
|
const startTime = Date.now();
|
|
await page.goto('/');
|
|
await page.waitForLoadState('networkidle');
|
|
const loadTime = Date.now() - startTime;
|
|
|
|
expect(loadTime).toBeLessThan(2000);
|
|
});
|
|
```
|
|
|
|
**Step 2: 运行测试验证失败**
|
|
|
|
Run: `cd e2e && npm run test:performance -- --grep "首页应该在2秒内完成加载"`
|
|
|
|
Expected: FAIL - 页面加载时间超过2秒
|
|
|
|
**Step 3: 配置代码分割和优化**
|
|
|
|
```javascript
|
|
// next.config.mjs
|
|
/** @type {import('next').NextConfig} */
|
|
const nextConfig = {
|
|
reactStrictMode: true,
|
|
swcMinify: true,
|
|
compress: true,
|
|
images: {
|
|
formats: ['image/avif', 'image/webp'],
|
|
deviceSizes: [640, 750, 828, 1080, 1200, 1920],
|
|
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
|
|
},
|
|
experimental: {
|
|
optimizeCss: true,
|
|
},
|
|
};
|
|
|
|
export default nextConfig;
|
|
```
|
|
|
|
**Step 4: 创建加载状态组件**
|
|
|
|
```typescript
|
|
// src/app/loading.tsx
|
|
export default function Loading() {
|
|
return (
|
|
<div className="flex items-center justify-center min-h-screen">
|
|
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600"></div>
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
|
|
**Step 5: 运行测试验证通过**
|
|
|
|
Run: `cd e2e && npm run test:performance -- --grep "首页应该在2秒内完成加载"`
|
|
|
|
Expected: PASS
|
|
|
|
**Step 6: 提交**
|
|
|
|
```bash
|
|
git add next.config.mjs src/app/loading.tsx
|
|
git commit -m "perf: optimize page load time with code splitting and image optimization"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 5: 改善交互响应时间
|
|
|
|
**背景:** 性能测试显示交互响应时间需要优化
|
|
|
|
**Files:**
|
|
- Modify: `src/components/Header.tsx`, `src/components/Button.tsx`
|
|
- Test: `e2e/src/tests/performance/performance.spec.ts`
|
|
|
|
**Step 1: 编写失败的测试**
|
|
|
|
```typescript
|
|
// e2e/src/tests/performance/performance.spec.ts
|
|
test('按钮点击应该在100ms内响应', async ({ page }) => {
|
|
await page.goto('/');
|
|
const button = page.locator('button:has-text("立即咨询")').first();
|
|
|
|
const startTime = Date.now();
|
|
await button.click();
|
|
const responseTime = Date.now() - startTime;
|
|
|
|
expect(responseTime).toBeLessThan(100);
|
|
});
|
|
```
|
|
|
|
**Step 2: 运行测试验证失败**
|
|
|
|
Run: `cd e2e && npm run test:performance -- --grep "按钮点击应该在100ms内响应"`
|
|
|
|
Expected: FAIL - 按钮响应时间超过100ms
|
|
|
|
**Step 3: 优化按钮组件**
|
|
|
|
```typescript
|
|
// src/components/Button.tsx
|
|
'use client';
|
|
|
|
import { forwardRef } from 'react';
|
|
|
|
export const Button = forwardRef<HTMLButtonElement, React.ButtonHTMLAttributes<HTMLButtonElement>>(
|
|
({ children, onClick, ...props }, ref) => {
|
|
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
|
|
requestAnimationFrame(() => {
|
|
onClick?.(e);
|
|
});
|
|
};
|
|
|
|
return (
|
|
<button
|
|
ref={ref}
|
|
onClick={handleClick}
|
|
className="..."
|
|
{...props}
|
|
>
|
|
{children}
|
|
</button>
|
|
);
|
|
}
|
|
);
|
|
|
|
Button.displayName = 'Button';
|
|
```
|
|
|
|
**Step 4: 运行测试验证通过**
|
|
|
|
Run: `cd e2e && npm run test:performance -- --grep "按钮点击应该在100ms内响应"`
|
|
|
|
Expected: PASS
|
|
|
|
**Step 5: 提交**
|
|
|
|
```bash
|
|
git add src/components/Button.tsx
|
|
git commit -m "perf: improve button click response time with requestAnimationFrame"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 6: 优化滚动性能
|
|
|
|
**背景:** 性能测试显示滚动性能需要改善
|
|
|
|
**Files:**
|
|
- Create: `src/hooks/useThrottle.ts`
|
|
- Modify: `src/components/Header.tsx`
|
|
- Test: `e2e/src/tests/performance/performance.spec.ts`
|
|
|
|
**Step 1: 编写失败的测试**
|
|
|
|
```typescript
|
|
// e2e/src/tests/performance/performance.spec.ts
|
|
test('滚动帧率应该保持在60fps', async ({ page }) => {
|
|
await page.goto('/');
|
|
|
|
const frameRates: number[] = [];
|
|
|
|
for (let i = 0; i < 10; i++) {
|
|
await page.evaluate(() => {
|
|
window.scrollBy(0, 100);
|
|
});
|
|
await page.waitForTimeout(100);
|
|
|
|
const fps = await page.evaluate(() => {
|
|
return (window as any).performance?.fps || 60;
|
|
});
|
|
frameRates.push(fps);
|
|
}
|
|
|
|
const avgFps = frameRates.reduce((a, b) => a + b, 0) / frameRates.length;
|
|
expect(avgFps).toBeGreaterThan(55);
|
|
});
|
|
```
|
|
|
|
**Step 2: 运行测试验证失败**
|
|
|
|
Run: `cd e2e && npm run test:performance -- --grep "滚动帧率应该保持在60fps"`
|
|
|
|
Expected: FAIL - 滚动帧率低于55fps
|
|
|
|
**Step 3: 创建节流Hook**
|
|
|
|
```typescript
|
|
// src/hooks/useThrottle.ts
|
|
import { useCallback, useRef } from 'react';
|
|
|
|
export function useThrottle<T extends (...args: any[]) => any>(
|
|
callback: T,
|
|
delay: number
|
|
): T {
|
|
const lastRan = useRef(Date.now());
|
|
|
|
return useCallback(
|
|
(...args: Parameters<T>) => {
|
|
if (Date.now() - lastRan.current >= delay) {
|
|
callback(...args);
|
|
lastRan.current = Date.now();
|
|
}
|
|
},
|
|
[callback, delay]
|
|
) as T;
|
|
}
|
|
```
|
|
|
|
**Step 4: 应用节流优化滚动事件**
|
|
|
|
```typescript
|
|
// src/components/Header.tsx
|
|
import { useThrottle } from '@/hooks/useThrottle';
|
|
|
|
export default function Header() {
|
|
const handleScroll = useThrottle(() => {
|
|
const isScrolled = window.scrollY > 50;
|
|
// 更新滚动状态
|
|
}, 100);
|
|
|
|
useEffect(() => {
|
|
window.addEventListener('scroll', handleScroll);
|
|
return () => window.removeEventListener('scroll', handleScroll);
|
|
}, [handleScroll]);
|
|
}
|
|
```
|
|
|
|
**Step 5: 运行测试验证通过**
|
|
|
|
Run: `cd e2e && npm run test:performance -- --grep "滚动帧率应该保持在60fps"`
|
|
|
|
Expected: PASS
|
|
|
|
**Step 6: 提交**
|
|
|
|
```bash
|
|
git add src/hooks/useThrottle.ts src/components/Header.tsx
|
|
git commit -m "perf: optimize scroll performance with throttle"
|
|
```
|
|
|
|
---
|
|
|
|
## 阶段3: 优先级3 - 响应式改进
|
|
|
|
### Task 7: 完善移动端布局
|
|
|
|
**背景:** 响应式测试显示移动端布局需要完善
|
|
|
|
**Files:**
|
|
- Modify: `src/app/contact/page.tsx`, `src/components/Header.tsx`
|
|
- Test: `e2e/src/tests/responsive/responsive.spec.ts`
|
|
|
|
**Step 1: 编写失败的测试**
|
|
|
|
```typescript
|
|
// e2e/src/tests/responsive/responsive.spec.ts
|
|
test('移动端布局应该正确显示', async ({ page }) => {
|
|
await page.setViewportSize({ width: 375, height: 667 });
|
|
await page.goto('/contact');
|
|
|
|
const form = page.locator('form');
|
|
const isVisible = await form.isVisible();
|
|
|
|
expect(isVisible).toBeTruthy();
|
|
|
|
const formWidth = await form.evaluate(el => el.getBoundingClientRect().width);
|
|
expect(formWidth).toBeLessThan(375);
|
|
});
|
|
```
|
|
|
|
**Step 2: 运行测试验证失败**
|
|
|
|
Run: `cd e2e && npm run test:responsive -- --grep "移动端布局应该正确显示"`
|
|
|
|
Expected: FAIL - 移动端布局未优化
|
|
|
|
**Step 3: 优化移动端表单布局**
|
|
|
|
```typescript
|
|
// src/app/contact/page.tsx
|
|
export default function ContactPage() {
|
|
return (
|
|
<div className="container mx-auto px-4 py-8">
|
|
<form className="grid grid-cols-1 md:grid-cols-2 gap-6 max-w-4xl mx-auto">
|
|
<div className="md:col-span-2">
|
|
<label className="block text-sm font-medium mb-2">姓名</label>
|
|
<input
|
|
type="text"
|
|
name="name"
|
|
className="w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500"
|
|
required
|
|
/>
|
|
</div>
|
|
|
|
<div>
|
|
<label className="block text-sm font-medium mb-2">邮箱</label>
|
|
<input
|
|
type="email"
|
|
name="email"
|
|
className="w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500"
|
|
required
|
|
/>
|
|
</div>
|
|
|
|
<div>
|
|
<label className="block text-sm font-medium mb-2">电话</label>
|
|
<input
|
|
type="tel"
|
|
name="phone"
|
|
className="w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500"
|
|
/>
|
|
</div>
|
|
|
|
<div className="md:col-span-2">
|
|
<label className="block text-sm font-medium mb-2">消息</label>
|
|
<textarea
|
|
name="message"
|
|
rows={4}
|
|
className="w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500"
|
|
required
|
|
/>
|
|
</div>
|
|
|
|
<div className="md:col-span-2">
|
|
<button
|
|
type="submit"
|
|
className="w-full bg-blue-600 text-white py-3 rounded-lg hover:bg-blue-700 transition-colors"
|
|
>
|
|
提交
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
|
|
**Step 4: 运行测试验证通过**
|
|
|
|
Run: `cd e2e && npm run test:responsive -- --grep "移动端布局应该正确显示"`
|
|
|
|
Expected: PASS
|
|
|
|
**Step 5: 提交**
|
|
|
|
```bash
|
|
git add src/app/contact/page.tsx
|
|
git commit -m "style: improve mobile responsive layout for contact form"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 8: 优化平板端显示
|
|
|
|
**背景:** 响应式测试显示平板端显示需要调整
|
|
|
|
**Files:**
|
|
- Modify: `src/app/contact/page.tsx`, `src/components/Header.tsx`
|
|
- Test: `e2e/src/tests/responsive/responsive.spec.ts`
|
|
|
|
**Step 1: 编写失败的测试**
|
|
|
|
```typescript
|
|
// e2e/src/tests/responsive/responsive.spec.ts
|
|
test('平板端布局应该正确显示', async ({ page }) => {
|
|
await page.setViewportSize({ width: 768, height: 1024 });
|
|
await page.goto('/contact');
|
|
|
|
const form = page.locator('form');
|
|
const isVisible = await form.isVisible();
|
|
|
|
expect(isVisible).toBeTruthy();
|
|
|
|
const formWidth = await form.evaluate(el => el.getBoundingClientRect().width);
|
|
expect(formWidth).toBeGreaterThan(700);
|
|
expect(formWidth).toBeLessThan(768);
|
|
});
|
|
```
|
|
|
|
**Step 2: 运行测试验证失败**
|
|
|
|
Run: `cd e2e && npm run test:responsive -- --grep "平板端布局应该正确显示"`
|
|
|
|
Expected: FAIL - 平板端布局未优化
|
|
|
|
**Step 3: 优化平板端布局**
|
|
|
|
```typescript
|
|
// src/app/contact/page.tsx
|
|
export default function ContactPage() {
|
|
return (
|
|
<div className="container mx-auto px-4 md:px-8 py-8 md:py-12">
|
|
<form className="grid grid-cols-1 md:grid-cols-2 gap-6 max-w-4xl mx-auto">
|
|
{/* 表单字段 - 使用md:前缀优化平板端 */}
|
|
</form>
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
|
|
**Step 4: 运行测试验证通过**
|
|
|
|
Run: `cd e2e && npm run test:responsive -- --grep "平板端布局应该正确显示"`
|
|
|
|
Expected: PASS
|
|
|
|
**Step 5: 提交**
|
|
|
|
```bash
|
|
git add src/app/contact/page.tsx
|
|
git commit -m "style: improve tablet responsive layout"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 9: 改善大屏幕体验
|
|
|
|
**背景:** 响应式测试显示大屏幕显示需要优化
|
|
|
|
**Files:**
|
|
- Modify: `src/app/contact/page.tsx`, `src/app/page.tsx`
|
|
- Test: `e2e/src/tests/responsive/responsive.spec.ts`
|
|
|
|
**Step 1: 编写失败的测试**
|
|
|
|
```typescript
|
|
// e2e/src/tests/responsive/responsive.spec.ts
|
|
test('大屏幕布局应该正确显示', async ({ page }) => {
|
|
await page.setViewportSize({ width: 1920, height: 1080 });
|
|
await page.goto('/contact');
|
|
|
|
const form = page.locator('form');
|
|
const isVisible = await form.isVisible();
|
|
|
|
expect(isVisible).toBeTruthy();
|
|
|
|
const formWidth = await form.evaluate(el => el.getBoundingClientRect().width);
|
|
expect(formWidth).toBeGreaterThan(1200);
|
|
expect(formWidth).toBeLessThan(1920);
|
|
});
|
|
```
|
|
|
|
**Step 2: 运行测试验证失败**
|
|
|
|
Run: `cd e2e && npm run test:responsive -- --grep "大屏幕布局应该正确显示"`
|
|
|
|
Expected: FAIL - 大屏幕布局未优化
|
|
|
|
**Step 3: 优化大屏幕布局**
|
|
|
|
```typescript
|
|
// src/app/contact/page.tsx
|
|
export default function ContactPage() {
|
|
return (
|
|
<div className="container mx-auto px-4 md:px-8 lg:px-16 py-8 md:py-12 lg:py-16">
|
|
<form className="grid grid-cols-1 md:grid-cols-2 gap-6 max-w-6xl mx-auto">
|
|
{/* 表单字段 - 使用lg:前缀优化大屏幕 */}
|
|
</form>
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
|
|
**Step 4: 运行测试验证通过**
|
|
|
|
Run: `cd e2e && npm run test:responsive -- --grep "大屏幕布局应该正确显示"`
|
|
|
|
Expected: PASS
|
|
|
|
**Step 5: 提交**
|
|
|
|
```bash
|
|
git add src/app/contact/page.tsx
|
|
git commit -m "style: improve large screen responsive layout"
|
|
```
|
|
|
|
---
|
|
|
|
## 验证和总结
|
|
|
|
### Task 10: 运行完整测试套件验证改进
|
|
|
|
**Files:**
|
|
- Test: `e2e/src/tests/**/*.spec.ts`
|
|
|
|
**Step 1: 运行所有测试**
|
|
|
|
Run: `cd e2e && npm run test:all-with-progress`
|
|
|
|
Expected: 所有测试通过率显著提升
|
|
|
|
**Step 2: 生成测试报告**
|
|
|
|
Run: `cd e2e && npm run test:report`
|
|
|
|
Expected: 生成详细的HTML测试报告
|
|
|
|
**Step 3: 更新测试报告文档**
|
|
|
|
Modify: `e2e/test-report.md`
|
|
|
|
添加改进前后的对比数据和总结
|
|
|
|
**Step 4: 提交**
|
|
|
|
```bash
|
|
git add e2e/test-report.md
|
|
git commit -m "docs: update test report with improvements"
|
|
```
|
|
|
|
---
|
|
|
|
## 执行策略
|
|
|
|
### TDD流程
|
|
每个任务都遵循以下TDD循环:
|
|
1. **Red**: 编写失败的测试
|
|
2. **Green**: 编写最小代码使测试通过
|
|
3. **Refactor**: 重构代码(如果需要)
|
|
4. **Commit**: 提交代码
|
|
|
|
### 测试优先级
|
|
- **冒烟测试**: 100%通过率(已达成)
|
|
- **回归测试**: 目标80%+通过率
|
|
- **性能测试**: 目标70%+通过率
|
|
- **响应式测试**: 目标80%+通过率
|
|
|
|
### 频繁提交
|
|
每个任务完成后立即提交,保持代码历史清晰
|
|
|
|
---
|
|
|
|
## 成功标准
|
|
|
|
- [ ] 回归测试通过率达到80%以上
|
|
- [ ] 性能测试通过率达到70%以上
|
|
- [ ] 响应式测试通过率达到80%以上
|
|
- [ ] 所有冒烟测试保持100%通过
|
|
- [ ] 页面加载时间优化到2秒以内
|
|
- [ ] 移动端菜单交互流畅
|
|
- [ ] 联系表单提交功能完整
|
|
- [ ] 平滑滚动正常工作
|
|
|
|
---
|
|
|
|
## 风险和缓解
|
|
|
|
### 风险1: 测试环境不稳定
|
|
**缓解**: 使用Playwright的重试机制和超时配置
|
|
|
|
### 风险2: 性能优化可能影响功能
|
|
**缓解**: 每次优化后运行完整测试套件验证
|
|
|
|
### 风险3: 响应式改动可能影响现有布局
|
|
**缓解**: 逐步实施,每个改动后测试所有断点
|
|
|
|
---
|
|
|
|
## 时间估算
|
|
|
|
- 阶段1(关键功能修复): 2-3小时
|
|
- 阶段2(性能优化): 2-3小时
|
|
- 阶段3(响应式改进): 1-2小时
|
|
- 验证和总结: 1小时
|
|
|
|
**总计**: 6-9小时
|