/** * 物品系统单元测试 * 测试纯函数,不依赖框架 */ describe('物品系统 - 纯函数测试', () => { describe('getQualityLevel - 品质等级计算', () => { const QUALITY_LEVELS = { 1: { level: 1, name: '垃圾', color: '#9e9e9e', range: [0, 49], multiplier: 0.5 }, 2: { level: 2, name: '普通', color: '#ffffff', range: [50, 99], multiplier: 1.0 }, 3: { level: 3, name: '优秀', color: '#1eff00', range: [100, 129], multiplier: 1.3 }, 4: { level: 4, name: '稀有', color: '#0070dd', range: [130, 159], multiplier: 1.6 }, 5: { level: 5, name: '史诗', color: '#a335ee', range: [160, 199], multiplier: 2.0 }, 6: { level: 6, name: '传说', color: '#ff8000', range: [200, 250], multiplier: 2.5 } } const getQualityLevel = (quality) => { const clampedQuality = Math.max(0, Math.min(250, quality)) for (const [level, data] of Object.entries(QUALITY_LEVELS)) { if (clampedQuality >= data.range[0] && clampedQuality <= data.range[1]) { return { level: parseInt(level), ...data } } } return QUALITY_LEVELS[1] } test('应该正确识别垃圾品质', () => { const level = getQualityLevel(0) expect(level.level).toBe(1) expect(level.name).toBe('垃圾') expect(level.multiplier).toBe(0.5) }) test('应该正确识别普通品质', () => { const level = getQualityLevel(75) expect(level.level).toBe(2) expect(level.name).toBe('普通') expect(level.multiplier).toBe(1.0) }) test('应该正确识别优秀品质', () => { const level = getQualityLevel(115) expect(level.level).toBe(3) expect(level.name).toBe('优秀') expect(level.multiplier).toBe(1.3) }) test('应该正确识别稀有品质', () => { const level = getQualityLevel(145) expect(level.level).toBe(4) expect(level.name).toBe('稀有') expect(level.multiplier).toBe(1.6) }) test('应该正确识别史诗品质', () => { const level = getQualityLevel(180) expect(level.level).toBe(5) expect(level.name).toBe('史诗') expect(level.multiplier).toBe(2.0) }) test('应该正确识别传说品质', () => { const level = getQualityLevel(220) expect(level.level).toBe(6) expect(level.name).toBe('传说') expect(level.multiplier).toBe(2.5) }) test('品质边界值测试', () => { expect(getQualityLevel(49).level).toBe(1) // 垃圾上限 expect(getQualityLevel(50).level).toBe(2) // 普通下限 expect(getQualityLevel(99).level).toBe(2) // 普通上限 expect(getQualityLevel(100).level).toBe(3) // 优秀下限 expect(getQualityLevel(250).level).toBe(6) // 传说上限 }) test('超出范围应该被限制', () => { expect(getQualityLevel(-10).level).toBe(1) // 负数 expect(getQualityLevel(300).level).toBe(6) // 超过250 }) }) describe('calculateItemStats - 物品属性计算', () => { test('应该正确计算武器伤害', () => { const baseDamage = 10 const quality = 100 const qualityMultiplier = 1.3 const qualityRatio = quality / 100 const finalDamage = Math.floor(baseDamage * qualityRatio * qualityMultiplier) expect(finalDamage).toBe(13) // 10 * 1.0 * 1.3 = 13 }) test('应该正确计算防御力', () => { const baseDefense = 20 const quality = 150 const qualityMultiplier = 1.6 const qualityRatio = quality / 100 const finalDefense = Math.floor(baseDefense * qualityRatio * qualityMultiplier) expect(finalDefense).toBe(48) // 20 * 1.5 * 1.6 = 48 }) test('应该正确计算物品价值', () => { const baseValue = 100 const quality = 120 const qualityMultiplier = 1.3 const qualityRatio = quality / 100 const finalValue = Math.floor(baseValue * qualityRatio * qualityMultiplier) expect(finalValue).toBe(156) // 100 * 1.2 * 1.3 = 156 }) test('品质为0时应该有最小值', () => { const baseDamage = 10 const quality = 0 const qualityMultiplier = 0.5 const qualityRatio = quality / 100 const finalDamage = Math.floor(baseDamage * qualityRatio * qualityMultiplier) expect(finalDamage).toBe(0) // 10 * 0 * 0.5 = 0 }) }) describe('generateRandomQuality - 随机品质生成', () => { test('基础品质范围应该是50-150', () => { const baseMin = 50 const baseMax = 150 const randomQuality = baseMin + Math.floor(Math.random() * (baseMax - baseMin + 1)) expect(randomQuality).toBeGreaterThanOrEqual(50) expect(randomQuality).toBeLessThanOrEqual(150) }) test('运气应该增加品质', () => { const baseQuality = 100 const luck = 20 const luckBonus = luck * 0.5 const finalQuality = baseQuality + luckBonus expect(finalQuality).toBe(110) // 100 + 20 * 0.5 = 110 }) test('品质应该被限制在0-250之间', () => { const clamp = (value) => Math.min(250, Math.max(0, value)) expect(clamp(-10)).toBe(0) expect(clamp(0)).toBe(0) expect(clamp(250)).toBe(250) expect(clamp(300)).toBe(250) }) test('传说品质应该非常稀有', () => { // 传说品质概率 < 0.02 const legendaryChance = 0.01 + 50 / 10000 expect(legendaryChance).toBeLessThan(0.02) }) test('史诗品质应该稀有', () => { // 史诗品质概率 < 0.08 const epicChance = 0.05 + 50 / 2000 expect(epicChance).toBeLessThan(0.08) }) }) describe('calculateSellPrice - 出售价格计算', () => { test('应该正确计算基础出售价格', () => { const baseValue = 100 const sellRate = 0.5 // 50% const sellPrice = Math.floor(baseValue * sellRate) expect(sellPrice).toBe(50) }) test('品质应该影响出售价格', () => { const baseValue = 100 const quality = 120 const qualityMultiplier = 1.3 const sellRate = 0.5 const sellPrice = Math.floor(baseValue * (quality / 100) * qualityMultiplier * sellRate) expect(sellPrice).toBe(78) // 100 * 1.2 * 1.3 * 0.5 = 78 }) test('市场倍率应该影响价格', () => { const baseValue = 100 const quality = 100 const qualityMultiplier = 1.0 const marketRate = 1.5 // 市场繁荣 const sellPrice = Math.floor(baseValue * 1.0 * qualityMultiplier * 0.5 * marketRate) expect(sellPrice).toBe(75) // 100 * 1.0 * 1.0 * 0.5 * 1.5 = 75 }) }) describe('calculateBuyPrice - 购买价格计算', () => { test('应该正确计算基础购买价格', () => { const baseValue = 100 const buyRate = 1.5 // 150% const buyPrice = Math.floor(baseValue * buyRate) expect(buyPrice).toBe(150) }) test('品质应该影响购买价格', () => { const baseValue = 100 const quality = 150 const qualityMultiplier = 1.6 const buyRate = 1.5 const buyPrice = Math.floor(baseValue * (quality / 100) * qualityMultiplier * buyRate) expect(buyPrice).toBe(360) // 100 * 1.5 * 1.6 * 1.5 = 360 }) }) describe('物品堆叠', () => { test('可堆叠物品应该有最大堆叠数', () => { const stackable = true const maxStack = 99 const canAddToStack = (currentStack, amount) => { return currentStack + amount <= maxStack } expect(canAddToStack(50, 40)).toBe(true) expect(canAddToStack(50, 49)).toBe(true) expect(canAddToStack(50, 50)).toBe(false) }) test('不可堆叠物品每次只能有一个', () => { const stackable = false const maxStack = 1 const canAddToStack = (currentStack) => { return currentStack < maxStack } expect(canAddToStack(0)).toBe(true) expect(canAddToStack(1)).toBe(false) }) test('使用堆叠物品应该减少数量', () => { const itemCount = 10 const useCount = 3 const remainingCount = itemCount - useCount expect(remainingCount).toBe(7) }) test('堆叠为0时物品应该被移除', () => { const itemCount = 1 const useCount = 1 const shouldRemove = itemCount - useCount <= 0 expect(shouldRemove).toBe(true) }) }) describe('装备物品', () => { test('武器应该装备到武器槽', () => { const itemType = 'weapon' const equipment = { weapon: null, armor: null } const canEquip = (slot) => { return equipment[slot] === null } expect(canEquip('weapon')).toBe(true) expect(canEquip('armor')).toBe(true) }) test('装备槽已占用时不能装备', () => { const equipment = { weapon: { id: 'old_sword' } } const canEquip = (slot) => { return equipment[slot] === null } expect(canEquip('weapon')).toBe(false) }) test('双手武器应该占用两个槽位', () => { const item = { id: 'two_handed_sword', twoHanded: true } const slotsNeeded = item.twoHanded ? 2 : 1 expect(slotsNeeded).toBe(2) }) }) describe('消耗品效果', () => { test('生命药水应该恢复生命值', () => { const currentHealth = 50 const maxHealth = 100 const healAmount = 30 const newHealth = Math.min(maxHealth, currentHealth + healAmount) expect(newHealth).toBe(80) }) test('生命值已满时不应该溢出', () => { const currentHealth = 100 const maxHealth = 100 const healAmount = 30 const newHealth = Math.min(maxHealth, currentHealth + healAmount) expect(newHealth).toBe(100) }) test('耐力药水应该恢复耐力', () => { const currentStamina = 20 const maxStamina = 100 const restoreAmount = 50 const newStamina = Math.min(maxStamina, currentStamina + restoreAmount) expect(newStamina).toBe(70) }) }) describe('边界条件', () => { test('品质为负数时应该设为0', () => { const quality = -10 const clampedQuality = Math.max(0, quality) expect(clampedQuality).toBe(0) }) test('品质超过250时应该设为250', () => { const quality = 300 const clampedQuality = Math.min(250, quality) expect(clampedQuality).toBe(250) }) test('物品价值不能为负数', () => { const baseValue = -100 const finalValue = Math.max(0, baseValue) expect(finalValue).toBe(0) }) test('伤害不能为负数', () => { const baseDamage = -10 const qualityRatio = 1.0 const qualityMultiplier = 1.0 const finalDamage = Math.max(0, Math.floor(baseDamage * qualityRatio * qualityMultiplier)) expect(finalDamage).toBe(0) }) }) })