/** * 分类管理API测试 * TDD: 先写测试,再实现功能 */ const request = require('supertest'); const express = require('express'); // 模拟Express应用 const app = express(); app.use(express.json()); // 测试数据 const testCategories = [ { name: '测试一级分类1', parent_id: null, level: 1 }, { name: '测试一级分类2', parent_id: null, level: 1 }, ]; describe('分类管理API测试', () => { // 测试1: 获取分类树 describe('GET /api/categories/tree', () => { test('应该返回分类树结构', async () => { const response = await request(app) .get('/api/categories/tree') .expect(200); expect(response.body.success).toBe(true); expect(Array.isArray(response.body.data)).toBe(true); // 每个一级分类应该有children属性 if (response.body.data.length > 0) { expect(response.body.data[0]).toHaveProperty('children'); } }); test('应该支持按层级筛选', async () => { const response = await request(app) .get('/api/categories/tree?level=1') .expect(200); expect(response.body.success).toBe(true); // 返回的都是一级分类 response.body.data.forEach(cat => { expect(cat.level).toBe(1); }); }); }); // 测试2: 创建分类 describe('POST /api/categories', () => { test('应该能创建一级分类', async () => { const newCategory = { name: '新材料分类', parent_id: null, level: 1, description: '测试描述' }; const response = await request(app) .post('/api/categories') .send(newCategory) .expect(200); expect(response.body.success).toBe(true); expect(response.body.data).toHaveProperty('id'); expect(response.body.data.name).toBe(newCategory.name); }); test('应该能在指定父分类下创建二级分类', async () => { // 先创建父分类 const parentResponse = await request(app) .post('/api/categories') .send({ name: '父分类', parent_id: null, level: 1 }); const parentId = parentResponse.body.data.id; // 创建子分类 const childCategory = { name: '子分类', parent_id: parentId, level: 2 }; const response = await request(app) .post('/api/categories') .send(childCategory) .expect(200); expect(response.body.success).toBe(true); expect(response.body.data.parent_id).toBe(parentId); expect(response.body.data.level).toBe(2); }); test('分类名称不能为空', async () => { const response = await request(app) .post('/api/categories') .send({ name: '', parent_id: null, level: 1 }) .expect(400); expect(response.body.success).toBe(false); expect(response.body.message).toContain('名称'); }); test('同一父分类下不能有重名子分类', async () => { // 创建父分类 const parent = await request(app) .post('/api/categories') .send({ name: '唯一父分类', parent_id: null, level: 1 }); // 创建第一个子分类 await request(app) .post('/api/categories') .send({ name: '同名子分类', parent_id: parent.body.data.id, level: 2 }); // 尝试创建同名子分类 const response = await request(app) .post('/api/categories') .send({ name: '同名子分类', parent_id: parent.body.data.id, level: 2 }) .expect(400); expect(response.body.success).toBe(false); }); }); // 测试3: 更新分类 describe('PUT /api/categories/:id', () => { test('应该能更新分类名称', async () => { // 先创建分类 const createResponse = await request(app) .post('/api/categories') .send({ name: '原名称', parent_id: null, level: 1 }); const categoryId = createResponse.body.data.id; // 更新分类 const response = await request(app) .put(`/api/categories/${categoryId}`) .send({ name: '新名称' }) .expect(200); expect(response.body.success).toBe(true); // 验证更新 const getResponse = await request(app) .get(`/api/categories/${categoryId}`) .expect(200); expect(getResponse.body.data.name).toBe('新名称'); }); test('不能将分类设置为自己的子分类', async () => { // 创建父分类 const parent = await request(app) .post('/api/categories') .send({ name: '父', parent_id: null, level: 1 }); // 创建子分类 const child = await request(app) .post('/api/categories') .send({ name: '子', parent_id: parent.body.data.id, level: 2 }); // 尝试将父分类的parent_id设为子分类(循环引用) const response = await request(app) .put(`/api/categories/${parent.body.data.id}`) .send({ parent_id: child.body.data.id }) .expect(400); expect(response.body.success).toBe(false); }); }); // 测试4: 删除分类 describe('DELETE /api/categories/:id', () => { test('应该能删除空分类', async () => { // 创建分类 const createResponse = await request(app) .post('/api/categories') .send({ name: '待删除', parent_id: null, level: 1 }); const categoryId = createResponse.body.data.id; // 删除分类 const response = await request(app) .delete(`/api/categories/${categoryId}`) .expect(200); expect(response.body.success).toBe(true); // 验证已删除 const getResponse = await request(app) .get(`/api/categories/${categoryId}`) .expect(404); }); test('删除一级分类应该级联删除二级分类', async () => { // 创建父分类 const parent = await request(app) .post('/api/categories') .send({ name: '父', parent_id: null, level: 1 }); // 创建子分类 const child = await request(app) .post('/api/categories') .send({ name: '子', parent_id: parent.body.data.id, level: 2 }); // 删除父分类 await request(app) .delete(`/api/categories/${parent.body.data.id}`) .expect(200); // 验证子分类也被删除 await request(app) .get(`/api/categories/${child.body.data.id}`) .expect(404); }); test('有商品的分类不应该被删除', async () => { // 创建分类 const category = await request(app) .post('/api/categories') .send({ name: '有商品的分类', parent_id: null, level: 1 }); // 在该分类下创建商品(模拟) // ... 创建商品逻辑 // 尝试删除分类 const response = await request(app) .delete(`/api/categories/${category.body.data.id}`) .expect(400); expect(response.body.success).toBe(false); expect(response.body.message).toContain('商品'); }); }); // 测试5: 批量导入时自动创建分类 describe('批量导入分类处理', () => { test('导入时应该自动创建不存在的一级分类', async () => { const importData = { products: [ { name: '测试商品', category_level1: '新一级分类', category_level2: '新二级分类' } ] }; const response = await request(app) .post('/api/products/batch-import') .send(importData) .expect(200); expect(response.body.success).toBe(true); // 验证分类已创建 const categories = await request(app) .get('/api/categories/tree') .expect(200); const level1Exists = categories.body.data.some( cat => cat.name === '新一级分类' ); expect(level1Exists).toBe(true); }); test('导入时应该自动创建不存在的二级分类', async () => { // 先创建一级分类 await request(app) .post('/api/categories') .send({ name: '已有的一级', parent_id: null, level: 1 }); // 导入带有新二级分类的商品 const importData = { products: [ { name: '测试商品2', category_level1: '已有的一级', category_level2: '新的二级' } ] }; await request(app) .post('/api/products/batch-import') .send(importData) .expect(200); // 验证二级分类已创建 const categories = await request(app) .get('/api/categories/tree') .expect(200); const parent = categories.body.data.find( cat => cat.name === '已有的一级' ); expect(parent).toBeTruthy(); expect(parent.children).toBeDefined(); const level2Exists = parent.children.some( child => child.name === '新的二级' ); expect(level2Exists).toBe(true); }); }); }); // 运行测试 if (require.main === module) { const { execSync } = require('child_process'); try { execSync('npx jest test-category-api.spec.js --verbose', { cwd: __dirname, stdio: 'inherit' }); } catch (e) { process.exit(1); } } module.exports = { app };