Files
butcem/src/shared/transactions.test.ts
T

133 lines
4.1 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, it } from "vitest";
import { toCsv, csvMoney } from "./csv";
import { transactionFormSchema } from "./schemas/transaction";
import { normalizeTags, transactionEffects } from "./transactions";
const A = "a".repeat(24);
const B = "b".repeat(24);
const C1 = "c".repeat(24);
const C2 = "d".repeat(24);
describe("transactionEffects", () => {
it("gelir +, gider −, transfer kaynaktan − hedefe +", () => {
expect(
transactionEffects({ type: "income", status: "posted", amountMinor: 500, accountId: A }),
).toEqual([{ accountId: A, deltaMinor: 500 }]);
expect(
transactionEffects({ type: "expense", status: "posted", amountMinor: 500, accountId: A }),
).toEqual([{ accountId: A, deltaMinor: -500 }]);
expect(
transactionEffects({
type: "transfer",
status: "posted",
amountMinor: 500,
accountId: A,
toAccountId: B,
}),
).toEqual([
{ accountId: A, deltaMinor: -500 },
{ accountId: B, deltaMinor: 500 },
]);
});
it("planlı, iptal ve silinmiş işlemler etkisizdir", () => {
for (const x of [
{ status: "planned" as const },
{ status: "void" as const },
{ status: "posted" as const, deleted: true },
]) {
expect(transactionEffects({ type: "expense", amountMinor: 1, accountId: A, ...x })).toEqual(
[],
);
}
});
});
describe("normalizeTags", () => {
it("küçük harf, kırpma, tekrar yok, en fazla 10", () => {
expect(normalizeTags(" Market, İNDİRİM ,market,,#tatil")).toEqual([
"market",
"indirim",
"tatil",
]);
expect(normalizeTags(Array.from({ length: 15 }, (_, i) => `e${i}`))).toHaveLength(10);
});
});
describe("transactionFormSchema", () => {
const base = { type: "expense", amount: "1.200,00", date: "2026-11-05", accountId: A };
it("tek kategorili gideri kabul eder ve tutarı kuruşa çevirir", () => {
const r = transactionFormSchema.parse({ ...base, categoryId: C1, tags: "ev, Ev" });
expect(r.amount).toBe(120000);
expect(r.categoryId).toBe(C1);
expect(r.tags).toEqual(["ev"]);
expect(r.splits).toEqual([]);
});
it("kategorisiz ve bölmesiz gideri reddeder", () => {
expect(transactionFormSchema.safeParse(base).success).toBe(false);
});
it("bölünmüş işlemde kalem toplamı tutara eşit olmalı", () => {
const ok = transactionFormSchema.safeParse({
...base,
splits: [
{ categoryId: C1, amount: "800" },
{ categoryId: C2, amount: "250" },
{ categoryId: C1, amount: "150,00" },
],
});
expect(ok.success).toBe(true);
const bad = transactionFormSchema.safeParse({
...base,
splits: [
{ categoryId: C1, amount: "800" },
{ categoryId: C2, amount: "250" },
],
});
expect(bad.success).toBe(false);
expect(bad.error?.issues[0]?.path).toEqual(["splits"]);
const single = transactionFormSchema.safeParse({
...base,
splits: [{ categoryId: C1, amount: "1200" }],
});
expect(single.success).toBe(false);
});
it("transfer: hedef zorunlu, kaynaktan farklı", () => {
expect(transactionFormSchema.safeParse({ ...base, type: "transfer" }).success).toBe(false);
expect(
transactionFormSchema.safeParse({ ...base, type: "transfer", toAccountId: A }).success,
).toBe(false);
expect(
transactionFormSchema.safeParse({ ...base, type: "transfer", toAccountId: B }).success,
).toBe(true);
});
it("sıfır, negatif ve geçersiz tutarı reddeder", () => {
for (const amount of ["0", "-5", "abc", ""]) {
expect(
transactionFormSchema.safeParse({ ...base, categoryId: C1, amount }).success,
amount,
).toBe(false);
}
});
});
describe("CSV", () => {
it("BOM, noktalı virgül, kaçış ve formül enjeksiyonu koruması", () => {
const csv = toCsv(
["A", "B"],
[
["x;y", '"tırnak"'],
["=HYPERLINK(1)", csvMoney(-125050)],
],
);
expect(csv.startsWith("")).toBe(true);
expect(csv).toContain('"x;y";"""tırnak"""');
expect(csv).toContain("'=HYPERLINK(1);-1250,50");
expect(csv.endsWith("\r\n")).toBe(true);
});
});