import { describe, it, expect, beforeAll, afterAll } from '@jest/globals'; import request from 'supertest'; import { app } from '../api/app'; import { initDatabase } from '../api/database'; // 测试数据 const testUser = { name: '测试用户', phone: '13800138000', password: 'test123' }; const testCategory = { name: '测试类别', description: '测试类别描述' }; const testSubject = { name: '测试科目', totalScore: 100, timeLimitMinutes: 60, typeRatios: { single: 40, multiple: 30, judgment: 30 }, categoryRatios: { '通用': 100 } }; const testQuestion = { content: '测试题目内容', type: 'single', options: ['选项A', '选项B', '选项C', '选项D'], answer: '选项A', score: 10, category: '通用' }; describe('OpenSpec 1.1.0 功能测试', () => { let server: any; let userId: string; let categoryId: string; let subjectId: string; let questionId: string; let taskId: string; let adminToken: string; beforeAll(async () => { // 初始化数据库 await initDatabase(); // 启动测试服务器 server = app.listen(0); // 创建管理员用户并获取token const adminLogin = await request(server) .post('/api/admin/login') .send({ username: 'admin', password: 'admin123' }); adminToken = adminLogin.body.data.token; }); afterAll(async () => { if (server) { server.close(); } }); describe('1. 题目类别管理', () => { it('应该创建题目类别', async () => { const response = await request(server) .post('/api/admin/question-categories') .set('Authorization', `Bearer ${adminToken}`) .send(testCategory); expect(response.status).toBe(200); expect(response.body.success).toBe(true); expect(response.body.data.name).toBe(testCategory.name); categoryId = response.body.data.id; }); it('应该获取题目类别列表', async () => { const response = await request(server) .get('/api/question-categories'); expect(response.status).toBe(200); expect(response.body.success).toBe(true); expect(Array.isArray(response.body.data)).toBe(true); expect(response.body.data.length).toBeGreaterThan(0); }); it('应该更新题目类别', async () => { const updatedData = { ...testCategory, name: '更新后的类别' }; const response = await request(server) .put(`/api/admin/question-categories/${categoryId}`) .set('Authorization', `Bearer ${adminToken}`) .send(updatedData); expect(response.status).toBe(200); expect(response.body.success).toBe(true); expect(response.body.data.name).toBe('更新后的类别'); }); }); describe('2. 考试科目管理', () => { it('应该创建考试科目', async () => { const response = await request(server) .post('/api/admin/subjects') .set('Authorization', `Bearer ${adminToken}`) .send(testSubject); expect(response.status).toBe(200); expect(response.body.success).toBe(true); expect(response.body.data.name).toBe(testSubject.name); subjectId = response.body.data.id; }); it('应该获取考试科目列表', async () => { const response = await request(server) .get('/api/exam-subjects'); expect(response.status).toBe(200); expect(response.body.success).toBe(true); expect(Array.isArray(response.body.data)).toBe(true); expect(response.body.data.length).toBeGreaterThan(0); }); it('应该更新考试科目', async () => { const updatedData = { ...testSubject, name: '更新后的科目' }; const response = await request(server) .put(`/api/admin/subjects/${subjectId}`) .set('Authorization', `Bearer ${adminToken}`) .send(updatedData); expect(response.status).toBe(200); expect(response.body.success).toBe(true); expect(response.body.data.name).toBe('更新后的科目'); }); }); describe('3. 题目管理(带类别)', () => { it('应该创建带类别的题目', async () => { const questionWithCategory = { ...testQuestion, category: testCategory.name }; const response = await request(server) .post('/api/questions') .set('Authorization', `Bearer ${adminToken}`) .send(questionWithCategory); expect(response.status).toBe(200); expect(response.body.success).toBe(true); expect(response.body.data.category).toBe(testCategory.name); questionId = response.body.data.id; }); it('应该按类别筛选题目', async () => { const response = await request(server) .get('/api/questions') .query({ category: testCategory.name }); expect(response.status).toBe(200); expect(response.body.success).toBe(true); expect(response.body.data.length).toBeGreaterThan(0); expect(response.body.data[0].category).toBe(testCategory.name); }); }); describe('4. 用户管理', () => { it('应该创建用户', async () => { const response = await request(server) .post('/api/users') .send(testUser); expect(response.status).toBe(200); expect(response.body.success).toBe(true); expect(response.body.data.name).toBe(testUser.name); userId = response.body.data.id; }); it('应该验证用户密码', async () => { const response = await request(server) .post('/api/users/validate') .send({ name: testUser.name, phone: testUser.phone, password: testUser.password }); expect(response.status).toBe(200); expect(response.body.success).toBe(true); }); it('应该拒绝错误的密码', async () => { const response = await request(server) .post('/api/users/validate') .send({ name: testUser.name, phone: testUser.phone, password: 'wrongpassword' }); expect(response.status).toBe(400); expect(response.body.success).toBe(false); }); it('应该获取用户列表(管理员)', async () => { const response = await request(server) .get('/api/admin/users') .set('Authorization', `Bearer ${adminToken}`); expect(response.status).toBe(200); expect(response.body.success).toBe(true); expect(Array.isArray(response.body.data)).toBe(true); expect(response.body.data.length).toBeGreaterThan(0); }); }); describe('5. 考试任务管理', () => { it('应该创建考试任务', async () => { const taskData = { name: '测试任务', subjectId: subjectId, startAt: new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(), // 昨天 endAt: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(), // 明天 userIds: [userId] }; const response = await request(server) .post('/api/admin/tasks') .set('Authorization', `Bearer ${adminToken}`) .send(taskData); expect(response.status).toBe(200); expect(response.body.success).toBe(true); expect(response.body.data.name).toBe('测试任务'); taskId = response.body.data.id; }); it('应该获取用户任务列表', async () => { const response = await request(server) .get(`/api/exam-tasks/user/${userId}`); expect(response.status).toBe(200); expect(response.body.success).toBe(true); expect(Array.isArray(response.body.data)).toBe(true); expect(response.body.data.length).toBeGreaterThan(0); }); }); describe('6. 基于科目的答题', () => { it('应该基于科目生成试卷', async () => { const response = await request(server) .post('/api/quiz/generate') .send({ userId: userId, subjectId: subjectId }); expect(response.status).toBe(200); expect(response.body.success).toBe(true); expect(Array.isArray(response.body.data.questions)).toBe(true); expect(response.body.data.questions.length).toBeGreaterThan(0); expect(response.body.data.totalScore).toBe(testSubject.totalScore); expect(response.body.data.timeLimit).toBe(testSubject.timeLimitMinutes); }); it('应该基于任务生成试卷', async () => { const response = await request(server) .post('/api/quiz/generate') .send({ userId: userId, taskId: taskId }); expect(response.status).toBe(200); expect(response.body.success).toBe(true); expect(Array.isArray(response.body.data.questions)).toBe(true); expect(response.body.data.questions.length).toBeGreaterThan(0); }); }); describe('7. 答题提交(带科目/任务信息)', () => { let questions: any[]; beforeAll(async () => { // 获取题目用于测试 const response = await request(server) .post('/api/quiz/generate') .send({ userId: userId, subjectId: subjectId }); questions = response.body.data.questions; }); it('应该提交带科目信息的答案', async () => { const answers = questions.map((q: any) => ({ questionId: q.id, userAnswer: q.answer, score: q.score, isCorrect: true })); const response = await request(server) .post('/api/quiz/submit') .send({ userId: userId, subjectId: subjectId, answers: answers }); expect(response.status).toBe(200); expect(response.body.success).toBe(true); expect(response.body.data.recordId).toBeDefined(); }); it('应该提交带任务信息的答案', async () => { const answers = questions.map((q: any) => ({ questionId: q.id, userAnswer: q.answer, score: q.score, isCorrect: true })); const response = await request(server) .post('/api/quiz/submit') .send({ userId: userId, taskId: taskId, answers: answers }); expect(response.status).toBe(200); expect(response.body.success).toBe(true); expect(response.body.data.recordId).toBeDefined(); }); }); describe('8. 数据清理', () => { it('应该删除考试任务', async () => { const response = await request(server) .delete(`/api/admin/tasks/${taskId}`) .set('Authorization', `Bearer ${adminToken}`); expect(response.status).toBe(200); expect(response.body.success).toBe(true); }); it('应该删除考试科目', async () => { const response = await request(server) .delete(`/api/admin/subjects/${subjectId}`) .set('Authorization', `Bearer ${adminToken}`); expect(response.status).toBe(200); expect(response.body.success).toBe(true); }); it('应该删除题目类别', async () => { const response = await request(server) .delete(`/api/admin/question-categories/${categoryId}`) .set('Authorization', `Bearer ${adminToken}`); expect(response.status).toBe(200); expect(response.body.success).toBe(true); }); }); });