// Service-level tests for characterService (profile + energy countdown). const { describe, it, before, after } = require('node:test'); const assert = require('node:assert/strict'); const { setup, teardown, cleanup } = require('../helpers'); const NOW = 1_700_000_000_000; describe('characterService.getCharacterProfile', () => { let db, svc, time; before(async () => { await setup(); db = require('../../src/db').getDb(); svc = require('../../src/services/characterService'); time = require('../../src/utils/time'); time.setNow(() => NOW); }); after(async () => { time.resetNow(); await teardown(); cleanup(); }); function hero(n, energy, updatedAt) { const uid = Number(db.prepare('INSERT INTO users (username, password_hash, created_at) VALUES (?, ?, ?)').run(`cu${n}`, 'x', NOW).lastInsertRowid); const { id } = svc.createCharacter(uid, `CHero${n}`, 'mage'); db.prepare('UPDATE characters SET energy = ?, energy_updated_at = ? WHERE id = ?').run(energy, updatedAt, id); return uid; } it('REGRESSION: nextTickInSec is time to the NEXT +1, not time until full', () => { // 40/100 energy, last tick 60s ago → next +1 in 120s (regen is 180s per point) const p = svc.getCharacterProfile(hero(1, 40, NOW - 60_000)); assert.equal(p.energy.current, 40); assert.equal(p.energy.nextTickInSec, 120); }); it('nextTickInSec is 0 when energy is full', () => { const p = svc.getCharacterProfile(hero(2, 100, NOW)); assert.equal(p.energy.current, 100); assert.equal(p.energy.nextTickInSec, 0); }); it('applies offline regen when the profile is read', () => { // 10 energy, last tick 30 minutes ago → +10 const p = svc.getCharacterProfile(hero(3, 10, NOW - 30 * 60_000)); assert.equal(p.energy.current, 20); }); it('a new hero starts at full HP and full energy, timestamped "now" (not server start time)', () => { const uid = Number(db.prepare('INSERT INTO users (username, password_hash, created_at) VALUES (?, ?, ?)').run('cu4', 'x', NOW).lastInsertRowid); const { id } = svc.createCharacter(uid, 'CHero4', 'warrior'); const c = db.prepare('SELECT * FROM characters WHERE id = ?').get(id); assert.equal(c.energy, 100); assert.equal(c.energy_updated_at, NOW); assert.equal(c.hp_current, 135); // warrior L1: 50 + 8*10 + 5 }); });