mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-13 18:32:12 +03:00
Merged via /merge-batch (lote 2026-08-26 batch 2, v3.8.51). Boarded no worktree combinado junto com outras ~20 PRs; validação única: typecheck/complexity/cognitive-complexity/changelog-integrity verdes, file-size rebaseado onde necessário (crescimento legítimo), lint com os mesmos 228 achados pré-existentes confirmados via sonda contra o tip puro (não introduzidos por este lote), e 292 testes focados (unit) + 18 (vitest) passando. Obrigado pela contribuição.
179 lines
5.0 KiB
TypeScript
179 lines
5.0 KiB
TypeScript
import { describe, it } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import {
|
|
calculateLevel,
|
|
xpForLevel,
|
|
cumulativeXpForLevel,
|
|
xpToNextLevel,
|
|
getLevelTitle,
|
|
getLevelTier,
|
|
XP_REWARDS,
|
|
} from "../../../src/lib/gamification/xp";
|
|
|
|
describe("XP/Level Engine", () => {
|
|
describe("calculateLevel", () => {
|
|
it("returns level 1 for 0 XP", () => {
|
|
assert.equal(calculateLevel(0), 1);
|
|
});
|
|
|
|
it("returns level 1 for negative XP", () => {
|
|
assert.equal(calculateLevel(-100), 1);
|
|
});
|
|
|
|
it("falls back to level 1 for non-finite XP", () => {
|
|
assert.equal(calculateLevel(Number.NaN), 1);
|
|
assert.equal(calculateLevel(Number.POSITIVE_INFINITY), 1);
|
|
assert.equal(calculateLevel(Number.NEGATIVE_INFINITY), 1);
|
|
});
|
|
|
|
it("bounds finite XP above the safe integer range", () => {
|
|
assert.equal(calculateLevel(Number.MAX_VALUE), calculateLevel(Number.MAX_SAFE_INTEGER));
|
|
});
|
|
|
|
it("returns level 1 for small XP", () => {
|
|
assert.equal(calculateLevel(50), 1);
|
|
});
|
|
|
|
it("returns level 5 for 3162 XP", () => {
|
|
assert.equal(calculateLevel(3162), 5);
|
|
});
|
|
|
|
it("returns level 10 for cumulative level-10 XP", () => {
|
|
const xp = cumulativeXpForLevel(10);
|
|
assert.equal(calculateLevel(xp), 10);
|
|
});
|
|
|
|
it("returns level 25 for cumulative level-25 XP", () => {
|
|
const xp = cumulativeXpForLevel(25);
|
|
assert.equal(calculateLevel(xp), 25);
|
|
});
|
|
|
|
it("returns level 50 for cumulative level-50 XP", () => {
|
|
const xp = cumulativeXpForLevel(50);
|
|
assert.equal(calculateLevel(xp), 50);
|
|
});
|
|
|
|
it("matches every exact cumulative level boundary", () => {
|
|
for (let expected = 1; expected <= 100; expected++) {
|
|
assert.equal(calculateLevel(cumulativeXpForLevel(expected)), expected);
|
|
}
|
|
});
|
|
|
|
it("does not advance until the next cumulative boundary", () => {
|
|
for (let current = 1; current < 100; current++) {
|
|
const beforeNext = cumulativeXpForLevel(current + 1) - 1;
|
|
assert.equal(calculateLevel(beforeNext), current);
|
|
}
|
|
});
|
|
|
|
it("monotonically increases", () => {
|
|
let prev = 0;
|
|
for (let xp = 0; xp <= 100000; xp += 1000) {
|
|
const level = calculateLevel(xp);
|
|
assert.ok(level >= prev, `Level decreased at xp=${xp}: ${level} < ${prev}`);
|
|
prev = level;
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("xpForLevel", () => {
|
|
it("returns 0 for level 1", () => {
|
|
assert.equal(xpForLevel(1), 0);
|
|
});
|
|
|
|
it("returns positive XP for level > 1", () => {
|
|
assert.ok(xpForLevel(2) > 0);
|
|
});
|
|
|
|
it("increases with level", () => {
|
|
assert.ok(xpForLevel(10) > xpForLevel(5));
|
|
assert.ok(xpForLevel(50) > xpForLevel(10));
|
|
});
|
|
});
|
|
|
|
describe("cumulativeXpForLevel", () => {
|
|
it("returns 0 for level 1", () => {
|
|
assert.equal(cumulativeXpForLevel(1), 0);
|
|
});
|
|
|
|
it("increases with level", () => {
|
|
assert.ok(cumulativeXpForLevel(10) > cumulativeXpForLevel(5));
|
|
});
|
|
});
|
|
|
|
describe("xpToNextLevel", () => {
|
|
it("returns positive number", () => {
|
|
assert.ok(xpToNextLevel(0) > 0);
|
|
});
|
|
|
|
it("decreases as XP increases within same level", () => {
|
|
const at100 = xpToNextLevel(100);
|
|
const at200 = xpToNextLevel(200);
|
|
// Both should be level 1, but at200 is closer to level 2
|
|
if (calculateLevel(100) === calculateLevel(200)) {
|
|
assert.ok(at200 < at100);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("getLevelTitle", () => {
|
|
it("returns Beginner for level 1", () => {
|
|
assert.equal(getLevelTitle(1), "Beginner");
|
|
});
|
|
|
|
it("returns Explorer for level 11", () => {
|
|
assert.equal(getLevelTitle(11), "Explorer");
|
|
});
|
|
|
|
it("returns Expert for level 26", () => {
|
|
assert.equal(getLevelTitle(26), "Expert");
|
|
});
|
|
|
|
it("returns Master for level 51", () => {
|
|
assert.equal(getLevelTitle(51), "Master");
|
|
});
|
|
|
|
it("returns Legend for level 76", () => {
|
|
assert.equal(getLevelTitle(76), "Legend");
|
|
});
|
|
});
|
|
|
|
describe("getLevelTier", () => {
|
|
it("returns bronze for level 1", () => {
|
|
assert.equal(getLevelTier(1), "bronze");
|
|
});
|
|
|
|
it("returns silver for level 11", () => {
|
|
assert.equal(getLevelTier(11), "silver");
|
|
});
|
|
|
|
it("returns gold for level 26", () => {
|
|
assert.equal(getLevelTier(26), "gold");
|
|
});
|
|
|
|
it("returns platinum for level 51", () => {
|
|
assert.equal(getLevelTier(51), "platinum");
|
|
});
|
|
|
|
it("returns diamond for level 76", () => {
|
|
assert.equal(getLevelTier(76), "diamond");
|
|
});
|
|
});
|
|
|
|
describe("XP_REWARDS", () => {
|
|
it("has all expected actions", () => {
|
|
assert.ok("request" in XP_REWARDS);
|
|
assert.ok("provider_switch" in XP_REWARDS);
|
|
assert.ok("combo_create" in XP_REWARDS);
|
|
assert.ok("token_share" in XP_REWARDS);
|
|
assert.ok("daily_login" in XP_REWARDS);
|
|
});
|
|
|
|
it("all rewards are positive", () => {
|
|
for (const [key, value] of Object.entries(XP_REWARDS)) {
|
|
assert.ok(value > 0, `${key} should be positive, got ${value}`);
|
|
}
|
|
});
|
|
});
|
|
});
|