109 lines
2.9 KiB
TypeScript
109 lines
2.9 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
calculateInitiative,
|
|
formatInitiativeModifier,
|
|
} from "../initiative.js";
|
|
|
|
describe("calculateInitiative", () => {
|
|
it("returns positive modifier for creature with expertise (Aboleth: DEX 9, CR 10, proficiency 2)", () => {
|
|
const result = calculateInitiative({
|
|
dexScore: 9,
|
|
cr: "10",
|
|
initiativeProficiency: 2,
|
|
});
|
|
// DEX mod = floor((9-10)/2) = -1, PB for CR 10 = 4, -1 + 2*4 = +7
|
|
expect(result.modifier).toBe(7);
|
|
expect(result.passive).toBe(17);
|
|
});
|
|
|
|
it("returns negative modifier for low DEX with no proficiency", () => {
|
|
const result = calculateInitiative({
|
|
dexScore: 8,
|
|
cr: "1",
|
|
initiativeProficiency: 0,
|
|
});
|
|
// DEX mod = floor((8-10)/2) = -1, 0 * PB = 0, -1 + 0 = -1
|
|
expect(result.modifier).toBe(-1);
|
|
expect(result.passive).toBe(9);
|
|
});
|
|
|
|
it("returns zero modifier for DEX 10 with no proficiency", () => {
|
|
const result = calculateInitiative({
|
|
dexScore: 10,
|
|
cr: "1",
|
|
initiativeProficiency: 0,
|
|
});
|
|
expect(result.modifier).toBe(0);
|
|
expect(result.passive).toBe(10);
|
|
});
|
|
|
|
it("adds single proficiency bonus (multiplier 1)", () => {
|
|
const result = calculateInitiative({
|
|
dexScore: 14,
|
|
cr: "5",
|
|
initiativeProficiency: 1,
|
|
});
|
|
// DEX mod = +2, PB for CR 5 = 3, 2 + 1*3 = 5
|
|
expect(result.modifier).toBe(5);
|
|
expect(result.passive).toBe(15);
|
|
});
|
|
|
|
it("adds double proficiency bonus (multiplier 2 / expertise)", () => {
|
|
const result = calculateInitiative({
|
|
dexScore: 14,
|
|
cr: "5",
|
|
initiativeProficiency: 2,
|
|
});
|
|
// DEX mod = +2, PB for CR 5 = 3, 2 + 2*3 = 8
|
|
expect(result.modifier).toBe(8);
|
|
expect(result.passive).toBe(18);
|
|
});
|
|
|
|
it("handles no proficiency (multiplier 0) — reduces to raw DEX modifier", () => {
|
|
const result = calculateInitiative({
|
|
dexScore: 14,
|
|
cr: "5",
|
|
initiativeProficiency: 0,
|
|
});
|
|
// DEX mod = +2, 0 * PB = 0, 2 + 0 = 2
|
|
expect(result.modifier).toBe(2);
|
|
expect(result.passive).toBe(12);
|
|
});
|
|
|
|
it("handles negative result even with proficiency (very low DEX)", () => {
|
|
const result = calculateInitiative({
|
|
dexScore: 3,
|
|
cr: "0",
|
|
initiativeProficiency: 1,
|
|
});
|
|
// DEX mod = floor((3-10)/2) = -4, PB for CR 0 = 2, -4 + 1*2 = -2
|
|
expect(result.modifier).toBe(-2);
|
|
expect(result.passive).toBe(8);
|
|
});
|
|
|
|
it("handles fractional CR values", () => {
|
|
const result = calculateInitiative({
|
|
dexScore: 12,
|
|
cr: "1/4",
|
|
initiativeProficiency: 1,
|
|
});
|
|
// DEX mod = +1, PB for CR 1/4 = 2, 1 + 1*2 = 3
|
|
expect(result.modifier).toBe(3);
|
|
expect(result.passive).toBe(13);
|
|
});
|
|
});
|
|
|
|
describe("formatInitiativeModifier", () => {
|
|
it("formats positive modifier with plus sign", () => {
|
|
expect(formatInitiativeModifier(7)).toBe("+7");
|
|
});
|
|
|
|
it("formats negative modifier with U+2212 minus sign", () => {
|
|
expect(formatInitiativeModifier(-1)).toBe("\u22121");
|
|
});
|
|
|
|
it("formats zero modifier with plus sign", () => {
|
|
expect(formatInitiativeModifier(0)).toBe("+0");
|
|
});
|
|
});
|