Files
Emberfall/tests/unit/stats.test.js

139 lines
4.5 KiB
JavaScript

const test = require('node:test');
const assert = require('node:assert/strict');
const { calcDerived, computeEnergy, xpToNext, checkLevelUp, ENERGY_MAX } = require('../../src/game/stats');
// calcDerived tests
test('calcDerived warrior at level 1 with no equipment', () => {
const derived = calcDerived({ str: 8, agi: 4, int: 2, vit: 8 }, 1, 'warrior');
// maxHp = 50 + 8*10 + 1*5 = 135
assert.equal(derived.maxHp, 135);
// primary = str = 8, attack = 5 + 8*2 + 1 = 22
assert.equal(derived.attack, 22);
// defense = floor(8*1.5) = 12, +10% warrior = 13
assert.equal(derived.defense, 13);
// speed = 10 + 4 = 14
assert.equal(derived.speed, 14);
// critChance = min(40, 5 + floor(4*0.5)) = min(40, 7) = 7
assert.equal(derived.critChance, 7);
});
test('calcDerived mage at level 1 with no equipment', () => {
const derived = calcDerived({ str: 2, agi: 4, int: 9, vit: 5 }, 1, 'mage');
// maxHp = 50 + 5*10 + 1*5 = 105
assert.equal(derived.maxHp, 105);
// primary = int = 9, attack = 5 + 9*2 + 1 = 24
assert.equal(derived.attack, 24);
// defense = floor(5*1.5) = 7 (no warrior bonus)
assert.equal(derived.defense, 7);
// speed = 10 + 4 = 14
assert.equal(derived.speed, 14);
// critChance = min(40, 5 + floor(4*0.5)) = 7
assert.equal(derived.critChance, 7);
});
test('calcDerived ranger at level 1 with no equipment', () => {
const derived = calcDerived({ str: 5, agi: 9, int: 3, vit: 5 }, 1, 'ranger');
// maxHp = 50 + 5*10 + 1*5 = 105
assert.equal(derived.maxHp, 105);
// primary = agi = 9, attack = 5 + 9*2 + 1 = 24
assert.equal(derived.attack, 24);
// defense = floor(5*1.5) = 7
assert.equal(derived.defense, 7);
// speed = 10 + 9 = 19
assert.equal(derived.speed, 19);
// critChance = min(40, 5 + floor(9*0.5)) + 8 = min(40, 9) + 8 = 17
assert.equal(derived.critChance, 17);
});
test('calcDerived with equipment bonuses', () => {
const derived = calcDerived(
{ str: 8, agi: 4, int: 2, vit: 8 },
1,
'warrior',
{ bonus_str: 2, bonus_attack: 5, bonus_defense: 3 }
);
// totalStr = 10, attack = 5 + 10*2 + 1 + 5 = 31
assert.equal(derived.attack, 31);
// totalVit = 8, defense = floor(8*1.5) = 12, +3 equip = 15, +10% = 16
assert.equal(derived.defense, 16);
});
// computeEnergy tests
test('computeEnergy no time passed', () => {
const result = computeEnergy(50, Date.now(), Date.now() - 1000);
assert.equal(result.energy, 50);
});
test('computeEnergy partial tick (less than 1 regen interval)', () => {
const now = Date.now();
const result = computeEnergy(50, now - 10000, now);
// 10s < 180s → no regen
assert.equal(result.energy, 50);
});
test('computeEnergy full tick', () => {
const now = Date.now();
const result = computeEnergy(50, now - 360000, now);
// 360s / 180s = 2 ticks
assert.equal(result.energy, 52);
});
test('computeEnergy caps at max', () => {
const now = Date.now();
const result = computeEnergy(100, now - 3600000, now);
assert.equal(result.energy, ENERGY_MAX);
});
test('computeEnergy clock going backwards', () => {
const result = computeEnergy(50, Date.now(), Date.now() - 100000);
assert.equal(result.energy, 50);
});
test('computeEnergy large gap', () => {
const now = Date.now();
const result = computeEnergy(30, now - 36000000, now); // 10 hours ago
assert.equal(result.energy, ENERGY_MAX);
});
// xpToNext tests
test('xpToNext level 1→2 is 100', () => {
assert.equal(xpToNext(1), 100);
});
test('xpToNext level 2→3 is 282', () => {
assert.equal(xpToNext(2), 282);
});
test('xpToNext level 5→6 is 1118', () => {
assert.equal(xpToNext(5), 1118);
});
// checkLevelUp tests
test('checkLevelUp no level up', () => {
const result = checkLevelUp(1, 50, 10);
assert.equal(result.newLevel, 1);
assert.equal(result.leveledUp, false);
assert.equal(result.totalXp, 60);
});
test('checkLevelUp exact threshold', () => {
const result = checkLevelUp(1, 90, 10);
assert.equal(result.newLevel, 2);
assert.equal(result.leveledUp, true);
assert.equal(result.totalXp, 0);
});
test('checkLevelUp multiple level ups', () => {
// L1→2 costs 100, L2→3 costs 282. Total 382 for 2 levels. 500 XP → 2 levels, 118 remaining.
const result = checkLevelUp(1, 0, 500);
assert.equal(result.newLevel, 3);
assert.equal(result.leveledUp, true);
assert.equal(result.totalXp, 118);
});
test('checkLevelUp grants 3 points per level', () => {
const result = checkLevelUp(1, 0, 282); // exactly enough for L1→L2
assert.equal(result.newLevel, 2);
assert.equal(result.unspentPoints, 3);
});