import { test, expect } from '@playwright/test' import * as fs from 'fs' import * as path from 'path' import * as jwt from 'jsonwebtoken' const BASE = 'http://localhost:3006/api' function getJwtSecret(): string { const envPath = path.resolve(__dirname, '..', '.env') const envContent = fs.readFileSync(envPath, 'utf8') const match = envContent.match(/^JWT_SECRET=(.+)$/m) return match ? match[1].trim() : 'test-jwt-secret-for-e2e-tests' } function signToken(payload: object): string { return jwt.sign(payload, getJwtSecret(), { expiresIn: '1h' }) } const testUserId = '000000000000000000000001' const testAdminId = '000000000000000000000002' const userToken = signToken({ userId: testUserId, phone: '13800138000', role: 'user' }) const adminToken = signToken({ userId: testAdminId, phone: '13800138001', role: 'admin' }) test.describe('Backend API (Playwright)', () => { test('GET /api/user/info returns 401 without token', async ({ request }) => { const res = await request.get(`${BASE}/user/info`) expect(res.status()).toBe(401) }) test('POST /api/user/send-code returns 200', async ({ request }) => { const res = await request.post(`${BASE}/user/send-code`, { data: { phone: '13800138000' }, }) expect(res.status()).toBe(200) const body = await res.json() expect(body.message).toBe('验证码已发送') }) test('POST /api/payment/create returns 401 without auth', async ({ request }) => { const res = await request.post(`${BASE}/payment/create`, { data: { plan: 'growth' }, }) expect(res.status()).toBe(401) }) test('POST /api/progress/checkin returns 401 without auth', async ({ request }) => { const res = await request.post(`${BASE}/progress/checkin`) expect(res.status()).toBe(401) }) test('POST /api/contribution returns 401 without auth', async ({ request }) => { const res = await request.post(`${BASE}/contribution`, { data: { company: 'Test', position: '前端工程师' }, }) expect(res.status()).toBe(401) }) test('GET /api/progress requires auth', async ({ request }) => { const res = await request.get(`${BASE}/progress`) expect(res.status()).toBe(401) }) test('GET /api/admin/check requires auth', async ({ request }) => { const res = await request.get(`${BASE}/admin/check`) expect(res.status()).toBe(401) }) // --- Feedback API --- test('POST /api/feedback returns 401 without token', async ({ request }) => { const res = await request.post(`${BASE}/feedback`, { data: { type: 'suggestion', content: 'test feedback' }, }) expect(res.status()).toBe(401) }) test('POST /api/feedback returns 400 with empty content', async ({ request }) => { const res = await request.post(`${BASE}/feedback`, { data: { content: '' }, headers: { Authorization: `Bearer ${userToken}` }, }) expect(res.status()).toBe(400) }) test('POST /api/feedback returns 201 with valid data', async ({ request }) => { const res = await request.post(`${BASE}/feedback`, { data: { type: 'bug', content: 'Playwright浏览器端测试提交的问题反馈', contact: 'test@test.com' }, headers: { Authorization: `Bearer ${userToken}` }, }) expect(res.status()).toBe(201) }) test('GET /api/feedback returns 403 for non-admin', async ({ request }) => { const res = await request.get(`${BASE}/feedback`, { headers: { Authorization: `Bearer ${userToken}` }, }) expect(res.status()).toBe(403) }) test('GET /api/feedback returns 200 for admin', async ({ request }) => { const res = await request.get(`${BASE}/feedback`, { headers: { Authorization: `Bearer ${adminToken}` }, }) expect(res.status()).toBe(200) const body = await res.json() expect(body.items).toBeDefined() expect(Array.isArray(body.items)).toBe(true) expect(body.total).toBeGreaterThanOrEqual(0) }) })