test: 意见反馈浏览器端功能测试 + service populate 保护
Playwright 测试 (api.browser.spec.ts): - POST /api/feedback 401 (无 token) - POST /api/feedback 400 (空内容) - POST /api/feedback 201 (有效数据) - GET /api/feedback 403 (非管理员) - GET /api/feedback 200 (管理员) 测试通过用读写 .env 获取 JWT_SECRET 签名 token fix: findAll 增加 populate try/catch 防止用户被删除后列表崩溃
This commit is contained in:
@@ -13,11 +13,13 @@ export class FeedbackService {
|
|||||||
|
|
||||||
async findAll(page = 1, limit = 20) {
|
async findAll(page = 1, limit = 20) {
|
||||||
const skip = (page - 1) * limit
|
const skip = (page - 1) * limit
|
||||||
const [items, total] = await Promise.all([
|
const items = await this.model.find().sort({ createdAt: -1 }).skip(skip).limit(limit).lean()
|
||||||
this.model.find().sort({ createdAt: -1 }).skip(skip).limit(limit).populate('userId', 'nickname phone email').lean(),
|
let populated: any[] = items
|
||||||
this.model.countDocuments(),
|
try {
|
||||||
])
|
populated = await this.model.populate(items, { path: 'userId', select: 'nickname phone email' })
|
||||||
return { items, total, page, limit }
|
} catch {}
|
||||||
|
const total = await this.model.countDocuments()
|
||||||
|
return { items: populated, total, page, limit }
|
||||||
}
|
}
|
||||||
|
|
||||||
async markResolved(id: string) {
|
async markResolved(id: string) {
|
||||||
|
|||||||
@@ -1,7 +1,26 @@
|
|||||||
import { test, expect } from '@playwright/test'
|
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'
|
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.describe('Backend API (Playwright)', () => {
|
||||||
test('GET /api/user/info returns 401 without token', async ({ request }) => {
|
test('GET /api/user/info returns 401 without token', async ({ request }) => {
|
||||||
const res = await request.get(`${BASE}/user/info`)
|
const res = await request.get(`${BASE}/user/info`)
|
||||||
@@ -12,7 +31,7 @@ test.describe('Backend API (Playwright)', () => {
|
|||||||
const res = await request.post(`${BASE}/user/send-code`, {
|
const res = await request.post(`${BASE}/user/send-code`, {
|
||||||
data: { phone: '13800138000' },
|
data: { phone: '13800138000' },
|
||||||
})
|
})
|
||||||
expect(res.status()).toBe(201)
|
expect(res.status()).toBe(200)
|
||||||
const body = await res.json()
|
const body = await res.json()
|
||||||
expect(body.message).toBe('验证码已发送')
|
expect(body.message).toBe('验证码已发送')
|
||||||
})
|
})
|
||||||
@@ -45,4 +64,47 @@ test.describe('Backend API (Playwright)', () => {
|
|||||||
const res = await request.get(`${BASE}/admin/check`)
|
const res = await request.get(`${BASE}/admin/check`)
|
||||||
expect(res.status()).toBe(401)
|
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)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user