/** * R46修复测试:点赞操作事务保护 * * 验证: * 1. 点赞/取消点赞代码中使用了 $transaction * 2. 删除记录和更新计数在同一事务中 */ describe('R46: 点赞操作事务保护测试', () => { test('点赞路由应该使用事务保护', async () => { const fs = require('fs') const path = require('path') const filePath = path.join(__dirname, '../../app/api/materials/like/route.ts') if (!fs.existsSync(filePath)) { console.log('跳过测试:文件不存在', filePath) return } const content = fs.readFileSync(filePath, 'utf-8') // 检查是否使用了 $transaction expect(content).toContain('$transaction') }) test('取消点赞应该在事务中执行删除和更新', async () => { const fs = require('fs') const path = require('path') const filePath = path.join(__dirname, '../../app/api/materials/like/route.ts') if (!fs.existsSync(filePath)) { console.log('跳过测试:文件不存在', filePath) return } const content = fs.readFileSync(filePath, 'utf-8') // 检查取消点赞部分是否包含事务 // 应该看到 tx.materialLike.delete 和 tx.material.update 在同一个 $transaction 块中 expect(content).toContain('tx.materialLike.delete') expect(content).toContain('tx.material.update') }) test('点赞应该在事务中执行创建和更新', async () => { const fs = require('fs') const path = require('path') const filePath = path.join(__dirname, '../../app/api/materials/like/route.ts') if (!fs.existsSync(filePath)) { console.log('跳过测试:文件不存在', filePath) return } const content = fs.readFileSync(filePath, 'utf-8') // 检查点赞部分是否包含事务 expect(content).toContain('tx.materialLike.create') }) test('不应该有独立的 prisma.materialLike 和 prisma.material 调用(应该都用 tx)', async () => { const fs = require('fs') const path = require('path') const filePath = path.join(__dirname, '../../app/api/materials/like/route.ts') if (!fs.existsSync(filePath)) { console.log('跳过测试:文件不存在', filePath) return } const content = fs.readFileSync(filePath, 'utf-8') // 统计事务内外的调用 const lines = content.split('\n') let inTransaction = false let independentMaterialLikeWrite = false let independentMaterialUpdate = false for (const line of lines) { if (line.includes('$transaction')) { inTransaction = true } // 检查是否有不在事务中的写操作 // 排除 findFirst(查询操作可以不在事务中) if (!inTransaction) { if (line.includes('prisma.materialLike.delete') || line.includes('prisma.materialLike.create')) { independentMaterialLikeWrite = true } if (line.includes('prisma.material.update') && (line.includes('increment') || line.includes('decrement'))) { independentMaterialUpdate = true } } } // 不应该有独立的写操作 expect(independentMaterialLikeWrite).toBe(false) expect(independentMaterialUpdate).toBe(false) }) })