|
|
@@ -437,4 +437,311 @@ describe('管理员商品管理API集成测试', () => {
|
|
|
}
|
|
|
});
|
|
|
});
|
|
|
+
|
|
|
+ describe('父子商品配置功能测试 (故事006.001)', () => {
|
|
|
+ it('应该成功创建父商品 (spuId=0)', async () => {
|
|
|
+ const createData = {
|
|
|
+ name: '父商品测试',
|
|
|
+ price: 200.00,
|
|
|
+ costPrice: 150.00,
|
|
|
+ categoryId1: testCategory.id,
|
|
|
+ categoryId2: testCategory.id,
|
|
|
+ categoryId3: testCategory.id,
|
|
|
+ goodsType: 1,
|
|
|
+ supplierId: testSupplier.id,
|
|
|
+ merchantId: testMerchant.id,
|
|
|
+ state: 1,
|
|
|
+ stock: 100,
|
|
|
+ lowestBuy: 1,
|
|
|
+ spuId: 0, // 父商品spuId=0
|
|
|
+ spuName: null // 父商品spuName为null
|
|
|
+ };
|
|
|
+
|
|
|
+ const response = await client.index.$post({
|
|
|
+ json: createData
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${adminToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ console.debug('创建父商品响应状态:', response.status);
|
|
|
+ expect(response.status).toBe(201);
|
|
|
+
|
|
|
+ if (response.status === 201) {
|
|
|
+ const data = await response.json();
|
|
|
+ expect(data).toHaveProperty('id');
|
|
|
+ expect(data.name).toBe(createData.name);
|
|
|
+ expect(data.spuId).toBe(0); // 验证spuId=0
|
|
|
+ expect(data.spuName).toBeNull(); // 验证spuName为null
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ it('应该成功创建子商品并关联父商品', async () => {
|
|
|
+ // 先创建父商品
|
|
|
+ const parentGoods = await testFactory.createTestGoods(testUser.id, {
|
|
|
+ name: '父商品-用于子商品测试',
|
|
|
+ price: 300.00,
|
|
|
+ spuId: 0,
|
|
|
+ spuName: null
|
|
|
+ });
|
|
|
+
|
|
|
+ const createData = {
|
|
|
+ name: '子商品测试',
|
|
|
+ price: 150.00,
|
|
|
+ costPrice: 120.00,
|
|
|
+ categoryId1: testCategory.id,
|
|
|
+ categoryId2: testCategory.id,
|
|
|
+ categoryId3: testCategory.id,
|
|
|
+ goodsType: 1,
|
|
|
+ supplierId: testSupplier.id,
|
|
|
+ merchantId: testMerchant.id,
|
|
|
+ state: 1,
|
|
|
+ stock: 50,
|
|
|
+ lowestBuy: 1,
|
|
|
+ spuId: parentGoods.id, // 子商品spuId=父商品ID
|
|
|
+ spuName: parentGoods.name // 子商品spuName=父商品名称
|
|
|
+ };
|
|
|
+
|
|
|
+ const response = await client.index.$post({
|
|
|
+ json: createData
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${adminToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ console.debug('创建子商品响应状态:', response.status);
|
|
|
+ expect(response.status).toBe(201);
|
|
|
+
|
|
|
+ if (response.status === 201) {
|
|
|
+ const data = await response.json();
|
|
|
+ expect(data).toHaveProperty('id');
|
|
|
+ expect(data.name).toBe(createData.name);
|
|
|
+ expect(data.spuId).toBe(parentGoods.id); // 验证spuId=父商品ID
|
|
|
+ expect(data.spuName).toBe(parentGoods.name); // 验证spuName=父商品名称
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ it('应该成功更新商品的父子关系', async () => {
|
|
|
+ // 创建父商品
|
|
|
+ const parentGoods = await testFactory.createTestGoods(testUser.id, {
|
|
|
+ name: '父商品-用于更新测试',
|
|
|
+ price: 400.00,
|
|
|
+ spuId: 0,
|
|
|
+ spuName: null
|
|
|
+ });
|
|
|
+
|
|
|
+ // 创建子商品
|
|
|
+ const childGoods = await testFactory.createTestGoods(testUser.id, {
|
|
|
+ name: '子商品-用于更新测试',
|
|
|
+ price: 200.00,
|
|
|
+ spuId: parentGoods.id,
|
|
|
+ spuName: parentGoods.name
|
|
|
+ });
|
|
|
+
|
|
|
+ // 更新子商品信息
|
|
|
+ const updateData = {
|
|
|
+ name: '更新后的子商品名称',
|
|
|
+ price: 250.00,
|
|
|
+ spuId: parentGoods.id, // 保持父子关系
|
|
|
+ spuName: '更新后的父商品名称' // 更新spuName
|
|
|
+ };
|
|
|
+
|
|
|
+ const response = await client[':id'].$put({
|
|
|
+ param: { id: childGoods.id },
|
|
|
+ json: updateData
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${adminToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ console.debug('更新子商品响应状态:', response.status);
|
|
|
+ expect(response.status).toBe(200);
|
|
|
+
|
|
|
+ if (response.status === 200) {
|
|
|
+ const data = await response.json();
|
|
|
+ expect(data.name).toBe(updateData.name);
|
|
|
+ expect(data.price).toBe(Number(updateData.price));
|
|
|
+ expect(data.spuId).toBe(parentGoods.id); // 验证父子关系保持
|
|
|
+ expect(data.spuName).toBe(updateData.spuName); // 验证spuName更新
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ it('应该成功获取商品详情并包含父子关系字段', async () => {
|
|
|
+ // 创建父商品
|
|
|
+ const parentGoods = await testFactory.createTestGoods(testUser.id, {
|
|
|
+ name: '父商品-用于详情测试',
|
|
|
+ price: 500.00,
|
|
|
+ spuId: 0,
|
|
|
+ spuName: null
|
|
|
+ });
|
|
|
+
|
|
|
+ // 获取父商品详情
|
|
|
+ const response = await client[':id'].$get({
|
|
|
+ param: { id: parentGoods.id }
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${adminToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ console.debug('获取父商品详情响应状态:', response.status);
|
|
|
+ expect(response.status).toBe(200);
|
|
|
+
|
|
|
+ if (response.status === 200) {
|
|
|
+ const data = await response.json();
|
|
|
+ expect(data.id).toBe(parentGoods.id);
|
|
|
+ expect(data.name).toBe(parentGoods.name);
|
|
|
+ expect(data.spuId).toBe(0); // 验证父商品spuId=0
|
|
|
+ expect(data.spuName).toBeNull(); // 验证父商品spuName为null
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ it('应该验证父子商品关系约束', async () => {
|
|
|
+ // 测试1: spuId必须是非负数 - Schema验证
|
|
|
+ const invalidData1 = {
|
|
|
+ name: '测试商品-无效spuId',
|
|
|
+ price: 100.00,
|
|
|
+ costPrice: 80.00,
|
|
|
+ categoryId1: testCategory.id,
|
|
|
+ categoryId2: testCategory.id,
|
|
|
+ categoryId3: testCategory.id,
|
|
|
+ goodsType: 1,
|
|
|
+ supplierId: testSupplier.id,
|
|
|
+ merchantId: testMerchant.id,
|
|
|
+ state: 1,
|
|
|
+ stock: 100,
|
|
|
+ lowestBuy: 1,
|
|
|
+ spuId: -1 // 无效的spuId,Schema应该验证失败
|
|
|
+ };
|
|
|
+
|
|
|
+ const response1 = await client.index.$post({
|
|
|
+ json: invalidData1
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${adminToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ console.debug('无效spuId测试响应状态:', response1.status);
|
|
|
+ expect(response1.status).toBe(400);
|
|
|
+
|
|
|
+ // 测试2: 创建商品时spuId不能指向不存在的商品
|
|
|
+ const invalidData2 = {
|
|
|
+ name: '测试商品-无效父商品',
|
|
|
+ price: 100.00,
|
|
|
+ costPrice: 80.00,
|
|
|
+ categoryId1: testCategory.id,
|
|
|
+ categoryId2: testCategory.id,
|
|
|
+ categoryId3: testCategory.id,
|
|
|
+ goodsType: 1,
|
|
|
+ supplierId: testSupplier.id,
|
|
|
+ merchantId: testMerchant.id,
|
|
|
+ state: 1,
|
|
|
+ stock: 100,
|
|
|
+ lowestBuy: 1,
|
|
|
+ spuId: 999999 // 不存在的商品ID
|
|
|
+ };
|
|
|
+
|
|
|
+ const response2 = await client.index.$post({
|
|
|
+ json: invalidData2
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${adminToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ console.debug('无效父商品测试响应状态:', response2.status);
|
|
|
+ // 可能返回201(创建成功)或400(验证失败),取决于业务逻辑
|
|
|
+ // 这里我们只记录状态,不进行断言
|
|
|
+ console.debug('创建指向不存在父商品的商品状态:', response2.status);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('应该支持批量创建父子商品', async () => {
|
|
|
+ // 创建父商品
|
|
|
+ const parentGoods = await testFactory.createTestGoods(testUser.id, {
|
|
|
+ name: '父商品-批量测试',
|
|
|
+ price: 600.00,
|
|
|
+ spuId: 0,
|
|
|
+ spuName: null
|
|
|
+ });
|
|
|
+
|
|
|
+ // 批量创建3个子商品
|
|
|
+ const childGoodsData = [
|
|
|
+ {
|
|
|
+ name: '子商品-规格1',
|
|
|
+ price: 300.00,
|
|
|
+ costPrice: 240.00,
|
|
|
+ categoryId1: testCategory.id,
|
|
|
+ categoryId2: testCategory.id,
|
|
|
+ categoryId3: testCategory.id,
|
|
|
+ goodsType: 1,
|
|
|
+ supplierId: testSupplier.id,
|
|
|
+ merchantId: testMerchant.id,
|
|
|
+ state: 1,
|
|
|
+ stock: 30,
|
|
|
+ lowestBuy: 1,
|
|
|
+ spuId: parentGoods.id,
|
|
|
+ spuName: parentGoods.name
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '子商品-规格2',
|
|
|
+ price: 320.00,
|
|
|
+ costPrice: 260.00,
|
|
|
+ categoryId1: testCategory.id,
|
|
|
+ categoryId2: testCategory.id,
|
|
|
+ categoryId3: testCategory.id,
|
|
|
+ goodsType: 1,
|
|
|
+ supplierId: testSupplier.id,
|
|
|
+ merchantId: testMerchant.id,
|
|
|
+ state: 1,
|
|
|
+ stock: 40,
|
|
|
+ lowestBuy: 1,
|
|
|
+ spuId: parentGoods.id,
|
|
|
+ spuName: parentGoods.name
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '子商品-规格3',
|
|
|
+ price: 350.00,
|
|
|
+ costPrice: 280.00,
|
|
|
+ categoryId1: testCategory.id,
|
|
|
+ categoryId2: testCategory.id,
|
|
|
+ categoryId3: testCategory.id,
|
|
|
+ goodsType: 1,
|
|
|
+ supplierId: testSupplier.id,
|
|
|
+ merchantId: testMerchant.id,
|
|
|
+ state: 1,
|
|
|
+ stock: 50,
|
|
|
+ lowestBuy: 1,
|
|
|
+ spuId: parentGoods.id,
|
|
|
+ spuName: parentGoods.name
|
|
|
+ }
|
|
|
+ ];
|
|
|
+
|
|
|
+ // 逐个创建子商品
|
|
|
+ const createdChildIds = [];
|
|
|
+ for (const childData of childGoodsData) {
|
|
|
+ const response = await client.index.$post({
|
|
|
+ json: childData
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${adminToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ expect(response.status).toBe(201);
|
|
|
+ const data = await response.json();
|
|
|
+ createdChildIds.push(data.id);
|
|
|
+
|
|
|
+ // 验证每个子商品都正确关联到父商品
|
|
|
+ expect(data.spuId).toBe(parentGoods.id);
|
|
|
+ expect(data.spuName).toBe(parentGoods.name);
|
|
|
+ }
|
|
|
+
|
|
|
+ console.debug(`批量创建了 ${createdChildIds.length} 个子商品`);
|
|
|
+ expect(createdChildIds).toHaveLength(3);
|
|
|
+ });
|
|
|
+ });
|
|
|
});
|