dodil/erp-ui
tests/format.test.ts
import { compareDecimal, formatAmount, formatMoney } from "../src/lib/format";
test("money is formatted as text, never through a float", () => {
expect(formatAmount("1234567.5")).toBe("1,234,567.50");
expect(formatAmount("9007199254740993.01")).toBe("9,007,199,254,740,993.01"); // past a float's precision
expect(formatAmount(0)).toBe("0.00"); // DataK3 renders a zero DECIMAL as 0
expect(formatAmount("-50")).toBe("-50.00");
expect(formatAmount(null)).toBe("—");
expect(formatMoney("2460.00", "EUR")).toBe("2,460.00 EUR");
});
test("decimals compare exactly where floats cannot", () => {
expect(compareDecimal("9007199254740993.00", "9007199254740992.50")).toBe(1);
expect(Number("9007199254740993.00") > Number("9007199254740992.50")).toBe(false); // why it matters
expect(compareDecimal("0.10", "0.1")).toBe(0);
expect(compareDecimal("-2", "1")).toBe(-1);
expect(compareDecimal("-2", "-10")).toBe(1);
expect(compareDecimal("0", "-0.00")).toBe(0);
expect(compareDecimal(null, "1")).toBe(1); // blanks sort last
});
test("decimals add exactly — a float sum would be off past 2^53 and at 0.1 + 0.2", async () => {
const { addDecimal, sumDecimal } = await import("../src/lib/format");
expect(addDecimal("0.10", "0.20")).toBe("0.3");
expect(0.1 + 0.2).not.toBe(0.3); // why it matters
expect(sumDecimal(["9007199254740993.01", "1.00"])).toBe("9007199254740994.01");
expect(String(Number("9007199254740993.01") + 1)).not.toBe("9007199254740994.01");
expect(sumDecimal(["15000.00", "-15000.00"])).toBe("0");
expect(sumDecimal(["-2.5", "1"])).toBe("-1.5");
expect(sumDecimal([0, "12.34", null])).toBe("12.34"); // a zero may arrive as the number 0
expect(sumDecimal([])).toBe("0");
});
test("ids past 2^53 survive JSON parsing; strings, decimals and safe integers are untouched", async () => {
const { parseJsonLossless, quoteUnsafeIntegers } = await import("../src/lib/json");
const text = '{"bp_id": 45665172796086509, "n": 3, "amount": "12.50", "p": 0.5, "note": "id 45665172796086509", "neg": -45665172796086509, "e": 1e21, "list": [9007199254740993]}';
expect(JSON.parse(text).bp_id).toBe(45665172796086510); // what JSON.parse does
const v = parseJsonLossless<Record<string, unknown>>(text);
expect(v.bp_id).toBe("45665172796086509");
expect(v.neg).toBe("-45665172796086509");
expect(v.list).toEqual(["9007199254740993"]);
expect(v.n).toBe(3);
expect(v.p).toBe(0.5);
expect(v.e).toBe(1e21);
expect(v.note).toBe("id 45665172796086509");
expect(quoteUnsafeIntegers('{"s":"a \\"quoted\\" 9007199254740993"}')).toBe('{"s":"a \\"quoted\\" 9007199254740993"}');
});