Files
text-adventure-game/tests/unit/systems/combatSystem.test.js
Claude cb412544e9 Initial commit: Text Adventure Game
Features:
- Combat system with AP/EP hit calculation and three-layer defense
- Auto-combat/farming mode
- Item system with stacking support
- Skill system with levels, milestones, and parent skill sync
- Shop system with dynamic pricing
- Inventory management with bulk selling
- Event system
- Game loop with offline earnings
- Save/Load system

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 17:13:51 +08:00

191 lines
5.3 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 战斗系统单元测试
* 测试纯函数,不依赖框架
*/
// 由于项目使用 ESM我们需要使用 require 直接导入
// 注意:这些测试假设代码已经被转换为 CommonJS 或者通过 babel 转换
describe('战斗系统 - 纯函数测试', () => {
describe('calculateHitRate - 命中概率计算', () => {
// 直接测试纯函数逻辑
const calculateHitRate = (ap, ep) => {
const ratio = ap / (ep + 1)
if (ratio >= 5) return 0.98
if (ratio >= 3) return 0.90
if (ratio >= 2) return 0.80
if (ratio >= 1.5) return 0.65
if (ratio >= 1) return 0.50
if (ratio >= 0.75) return 0.38
if (ratio >= 0.5) return 0.24
if (ratio >= 0.33) return 0.15
if (ratio >= 0.2) return 0.08
return 0.05
}
test('AP >> EP 时应该有高命中率', () => {
expect(calculateHitRate(50, 10)).toBe(0.90) // ratio = 4.5
expect(calculateHitRate(100, 10)).toBe(0.98) // ratio = 9.1
})
test('AP = EP 时应该有50%命中率', () => {
// ratio = 10 / (10 + 1) = 0.909 -> 实际上 > 0.75,所以是 0.38
expect(calculateHitRate(10, 10)).toBe(0.38)
// ratio = 20 / (20 + 1) = 0.95 -> 实际上 > 0.75,所以是 0.38
expect(calculateHitRate(20, 20)).toBe(0.38)
})
test('AP < EP 时应该有低命中率', () => {
// ratio = 10 / (20 + 1) = 0.476 -> < 0.5>= 0.33,所以是 0.15
expect(calculateHitRate(10, 20)).toBe(0.15)
// ratio = 5 / (20 + 1) = 0.238 -> >= 0.2,所以是 0.08
expect(calculateHitRate(5, 20)).toBe(0.08)
})
test('极低 AP/EP 比例时应该只有5%命中率', () => {
// ratio = 1 / (10 + 1) = 0.09 -> < 0.2,所以是 0.05
expect(calculateHitRate(1, 10)).toBe(0.05)
// ratio = 2 / (20 + 1) = 0.095 -> < 0.2,所以是 0.05
expect(calculateHitRate(2, 20)).toBe(0.05)
})
test('边界值测试', () => {
// ratio = 0 / (10 + 1) = 0 -> < 0.2,所以是 0.05
expect(calculateHitRate(0, 10)).toBe(0.05)
// ratio = 10 / (0 + 1) = 10 -> >= 5所以是 0.98
expect(calculateHitRate(10, 0)).toBe(0.98)
})
})
describe('AP/EP 计算逻辑验证', () => {
test('基础AP计算公式', () => {
// AP = 灵巧 + 智力*0.2
const dexterity = 10
const intuition = 10
const baseAP = dexterity + intuition * 0.2
expect(baseAP).toBe(12)
})
test('基础EP计算公式', () => {
// EP = 敏捷 + 智力*0.2
const agility = 8
const intuition = 10
const baseEP = agility + intuition * 0.2
expect(baseEP).toBe(10)
})
test('姿态加成计算', () => {
const baseAP = 10
const stances = {
attack: 1.1,
defense: 0.9,
balance: 1.0,
rapid: 1.05,
heavy: 1.15
}
expect(baseAP * stances.attack).toBe(11)
expect(baseAP * stances.defense).toBe(9)
expect(baseAP * stances.balance).toBe(10)
})
test('环境惩罚计算', () => {
const ap = 10
// 黑暗环境 -20%
expect(ap * 0.8).toBe(8)
// 恶劣环境 -10%
expect(ap * 0.9).toBe(9)
})
test('多敌人惩罚计算', () => {
const ap = 10
const enemyCount = 3
// 惩罚 = Math.min(0.3, (enemyCount - 1) * 0.05)
// 3个敌人 = (3-1)*0.05 = 0.10 = 10%
const penalty = Math.min(0.3, (enemyCount - 1) * 0.05)
expect(ap * (1 - penalty)).toBe(9)
})
test('耐力惩罚计算', () => {
const ap = 10
// 耐力耗尽
expect(ap * 0.5).toBe(5)
// 耐力25%
const staminaRatio = 0.25
expect(ap * (0.5 + staminaRatio * 0.5)).toBe(6.25)
})
})
describe('暴击系统计算', () => {
test('基础暴击率计算', () => {
// 基础暴击率 = 灵巧 / 100
const dexterity = 10
const baseCritRate = dexterity / 100
expect(baseCritRate).toBe(0.10)
})
test('暴击率上限', () => {
const critRate = 0.90
expect(Math.min(0.8, critRate)).toBe(0.80)
})
test('暴击倍数计算', () => {
const baseMult = 1.5
const bonusMult = 0.2
expect(baseMult + bonusMult).toBe(1.7)
})
})
describe('伤害计算验证', () => {
test('基础伤害公式', () => {
// 伤害 = 攻击力 * (1 - 防御减伤)
const damage = 100
const defense = 0.3 // 30%减伤
expect(damage * (1 - defense)).toBe(70)
})
test('最大防御减伤90%', () => {
const damage = 100
const maxDefense = 0.9
// 浮点数精度问题,使用 toBeCloseTo
expect(damage * (1 - maxDefense)).toBeCloseTo(10, 1)
})
test('暴击伤害', () => {
const damage = 100
const critMult = 1.5
expect(damage * critMult).toBe(150)
})
})
describe('边界条件测试', () => {
test('AP最小值为1', () => {
const ap = 0.5
expect(Math.max(1, Math.floor(ap))).toBe(1)
})
test('EP最小值为1', () => {
const ep = 0.3
expect(Math.max(1, Math.floor(ep))).toBe(1)
})
test('耐力不能为负数', () => {
const stamina = -10
const maxStamina = 100
const ratio = Math.max(0, stamina / maxStamina)
expect(ratio).toBe(0)
})
test('属性默认值处理', () => {
const baseStats = undefined
const dexterity = baseStats?.dexterity || 0
expect(dexterity).toBe(0)
})
})
})