/** * P4-API - 会员端团课高级搜索 API 测试 * 流程:会员登录 → 按课程类型筛选 → 按标签筛选 → 类型+标签组合筛选 → 验证结果 * * 使用 HTTP API(HMAC-SHA256 签名 + JWT Token) * 前置条件:后端服务 http://192.168.110.64:8084 已启动 */ const api = require('../helpers/api-helper'); let authToken = null; let memberId = null; let typeId = null; let labelId = null; describe('P4-API - 团课高级搜索', () => { // ════════════════════════════════════════════════════ // 步骤0:登录 & 准备筛选条件 // ════════════════════════════════════════════════════ beforeAll(async () => { console.log('════════════════════════════════════════════'); console.log('P4-API - 团课高级搜索测试'); console.log('════════════════════════════════════════════'); const result = await api.memberLogin(); expect(result).not.toBeNull(); authToken = result.accessToken; memberId = result.memberId; console.log(`[P4-API] 会员登录成功: memberId=${memberId}`); // 先获取课程类型列表,找第一个类型ID const typeRes = await api.getCourseTypes(); if (api.isSuccess(typeRes)) { const types = typeRes.data?.data || typeRes.data || []; const records = Array.isArray(types) ? types : (types.records || types.content || []); if (records.length > 0) { typeId = records[0].id; console.log(`[P4-API] 选择课程类型: id=${typeId}, name=${records[0].typeName || records[0].name}`); } } // 尝试从课程列表获取第一个标签ID try { const searchRes = await api.searchCourses('', authToken); if (api.isSuccess(searchRes)) { const content = searchRes.data?.data?.content || searchRes.data?.content || searchRes.data || []; const courses = Array.isArray(content) ? content : (content.records || []); // 从第一个课程取标签 for (const course of courses) { const labels = course.labels || course.labelList || []; if (Array.isArray(labels) && labels.length > 0) { const firstLabel = labels[0]; labelId = typeof firstLabel === 'object' ? firstLabel.id : firstLabel; const name = typeof firstLabel === 'object' ? firstLabel.labelName : ''; console.log(`[P4-API] 选择标签: id=${labelId}, name=${name}`); break; } } } } catch (e) { console.warn('[P4-API] 获取标签失败:', e.message); } }, 60000); // ════════════════════════════════════════════════════ // 步骤1:按课程类型筛选 // ════════════════════════════════════════════════════ describe('按课程类型筛选', () => { test('TC-SEARCH-001: 按类型筛选应返回正确结果', async () => { if (!typeId) { console.warn('[TC-SEARCH-001] 无类型ID,跳过'); return; } const res = await api.searchCoursesByType(typeId, authToken); expect(res.status).toBe(200); const content = res.data?.data?.content || res.data?.content || res.data || []; const courses = Array.isArray(content) ? content : (content.records || []); console.log(`[TC-SEARCH-001] 类型筛选结果: ${courses.length} 个课程`); // 验证所有返回课程的类型匹配 if (courses.length > 0) { courses.slice(0, 3).forEach(c => { console.log(` - ${c.courseName || c.name} (typeId=${c.courseTypeId || c.typeId})`); }); } expect(courses.length).toBeGreaterThanOrEqual(0); }); }); // ════════════════════════════════════════════════════ // 步骤2:按标签筛选 // ════════════════════════════════════════════════════ describe('按标签筛选', () => { test('TC-SEARCH-002: 按标签筛选应返回正确结果', async () => { if (!labelId) { console.warn('[TC-SEARCH-002] 无标签ID,跳过'); return; } const res = await api.searchCoursesByLabel(labelId, authToken); expect(res.status).toBe(200); const content = res.data?.data?.content || res.data?.content || res.data || []; const courses = Array.isArray(content) ? content : (content.records || []); console.log(`[TC-SEARCH-002] 标签筛选结果: ${courses.length} 个课程`); if (courses.length > 0) { courses.slice(0, 3).forEach(c => { const labels = (c.labels || c.labelList || []).map(l => typeof l === 'object' ? l.labelName : l ); console.log(` - ${c.courseName || c.name} (labels: [${labels.join(', ')}])`); }); } }); }); // ════════════════════════════════════════════════════ // 步骤3:类型+标签组合筛选 // ════════════════════════════════════════════════════ describe('类型+标签组合筛选', () => { test('TC-SEARCH-003: 组合筛选应返回交集结果', async () => { if (!typeId || !labelId) { console.warn('[TC-SEARCH-003] 缺少类型或标签ID,跳过'); return; } const res = await api.searchCoursesCombined(typeId, labelId, authToken); expect(res.status).toBe(200); const content = res.data?.data?.content || res.data?.content || res.data || []; const courses = Array.isArray(content) ? content : (content.records || []); console.log(`[TC-SEARCH-003] 组合筛选结果: ${courses.length} 个课程`); if (courses.length > 0) { courses.slice(0, 3).forEach(c => { console.log(` - ${c.courseName || c.name} (id=${c.id})`); }); } }); }); // ════════════════════════════════════════════════════ // 步骤4:边界场景 // ════════════════════════════════════════════════════ describe('边界场景', () => { test('TC-SEARCH-004: 搜索不存在类型返回200(后端可能忽略无效筛选)', async () => { const res = await api.searchCoursesByType(99999, authToken); // 应确保API正常响应,即使筛选参数无效也不应该崩溃 console.log(`[TC-SEARCH-004] 不存在类型: status=${res.status}`); expect(res.status).toBe(200); }); test('TC-SEARCH-005: 搜索不存在标签返回200(后端可能忽略无效筛选)', async () => { const res = await api.searchCoursesByLabel(99999, authToken); console.log(`[TC-SEARCH-005] 不存在标签: status=${res.status}`); expect(res.status).toBe(200); }); test('TC-SEARCH-006: 空关键词搜索可返回全部课程', async () => { const res = await api.searchCourses('', authToken); expect(res.status).toBe(200); const content = res.data?.data?.content || res.data?.content || res.data || []; const courses = Array.isArray(content) ? content : (content.records || []); console.log(`[TC-SEARCH-006] 空搜索返回: ${courses.length} 个课程`); expect(courses.length).toBeGreaterThanOrEqual(0); }); }); // ════════════════════════════════════════════════════ // 步骤5:总结 // ════════════════════════════════════════════════════ describe('总结', () => { test('TC-P4-SUMMARY: 团课高级搜索汇总', () => { console.log(''); console.log('════════════════════════════════════════════'); console.log('P4-API - 团课高级搜索测试结束'); console.log('════════════════════════════════════════════'); console.log(' 已测试:'); console.log(` 1. 按类型筛选 (typeId=${typeId || 'N/A'})`); console.log(` 2. 按标签筛选 (labelId=${labelId || 'N/A'})`); console.log(` 3. 类型+标签组合筛选`); console.log(' 4. 不存在类型/标签边界'); console.log(' 5. 空关键词搜索'); console.log('════════════════════════════════════════════'); expect(memberId).toBeDefined(); expect(authToken).toBeTruthy(); }); }); });