feat(recurring): düzenli işlem kuralları, planlı kayıt üretimi, onay/atla/ertele ve seri düzenleme
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
addDays,
|
||||
addMonths,
|
||||
describeRecurrence,
|
||||
isFinished,
|
||||
listOccurrences,
|
||||
occurrenceDate,
|
||||
type Recurrence,
|
||||
} from "./recurrence";
|
||||
|
||||
const rule = (over: Partial<Recurrence>): Recurrence => ({
|
||||
frequency: "monthly",
|
||||
interval: 1,
|
||||
monthlyMode: "day",
|
||||
startDate: "2026-01-31",
|
||||
endDate: null,
|
||||
count: null,
|
||||
...over,
|
||||
});
|
||||
|
||||
describe("tarih aritmetiği", () => {
|
||||
it("gün ve ay ekleme, ay sonu taşması", () => {
|
||||
expect(addDays("2026-12-30", 3)).toBe("2027-01-02");
|
||||
expect(addDays("2028-03-01", -1)).toBe("2028-02-29");
|
||||
expect(addMonths("2026-01-31", 1)).toBe("2026-02-28");
|
||||
expect(addMonths("2026-01-31", 1, 31)).toBe("2026-02-28");
|
||||
expect(addMonths("2026-11-15", 3)).toBe("2027-02-15");
|
||||
expect(addMonths("2026-04-10", 0, "last")).toBe("2026-04-30");
|
||||
});
|
||||
});
|
||||
|
||||
describe("occurrenceDate", () => {
|
||||
it("aylık: başlangıç günü korunur, ayda yoksa son gün", () => {
|
||||
const r = rule({});
|
||||
expect([0, 1, 2, 3].map((i) => occurrenceDate(r, i))).toEqual([
|
||||
"2026-01-31",
|
||||
"2026-02-28",
|
||||
"2026-03-31",
|
||||
"2026-04-30",
|
||||
]);
|
||||
});
|
||||
|
||||
it("aylık son gün modu (artık yıl dahil)", () => {
|
||||
const r = rule({ monthlyMode: "last", startDate: "2028-01-10" });
|
||||
expect([0, 1, 2].map((i) => occurrenceDate(r, i))).toEqual([
|
||||
"2028-01-31",
|
||||
"2028-02-29",
|
||||
"2028-03-31",
|
||||
]);
|
||||
});
|
||||
|
||||
it("günlük, haftalık (aralıkla), yıllık (29 Şubat)", () => {
|
||||
expect(
|
||||
occurrenceDate(rule({ frequency: "daily", interval: 3, startDate: "2026-11-30" }), 1),
|
||||
).toBe("2026-12-03");
|
||||
expect(
|
||||
occurrenceDate(rule({ frequency: "weekly", interval: 2, startDate: "2026-11-02" }), 2),
|
||||
).toBe("2026-11-30");
|
||||
const y = rule({ frequency: "yearly", startDate: "2028-02-29" });
|
||||
expect([1, 4].map((i) => occurrenceDate(y, i))).toEqual(["2029-02-28", "2032-02-29"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("listOccurrences", () => {
|
||||
it("tekrar sayısı, bitiş tarihi ve ufuk sınırları", () => {
|
||||
const r = rule({ startDate: "2026-01-05", count: 3 });
|
||||
expect(listOccurrences(r, "2030-01-01").map((o) => o.date)).toEqual([
|
||||
"2026-01-05",
|
||||
"2026-02-05",
|
||||
"2026-03-05",
|
||||
]);
|
||||
expect(isFinished(r, 3)).toBe(true);
|
||||
const e = rule({ startDate: "2026-01-05", endDate: "2026-02-10" });
|
||||
expect(listOccurrences(e, "2030-01-01")).toHaveLength(2);
|
||||
const h = rule({ startDate: "2026-01-05" });
|
||||
expect(listOccurrences(h, "2026-04-05").map((o) => o.index)).toEqual([0, 1, 2, 3]);
|
||||
expect(listOccurrences(h, "2026-04-05", 2).map((o) => o.index)).toEqual([2, 3]);
|
||||
expect(isFinished(h, 100)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("describeRecurrence", () => {
|
||||
it("Türkçe açıklama", () => {
|
||||
expect(describeRecurrence(rule({ startDate: "2026-11-03" }))).toBe("Her ay 3. gün");
|
||||
expect(describeRecurrence(rule({ monthlyMode: "last" }))).toBe("Her ayın son günü");
|
||||
expect(
|
||||
describeRecurrence(rule({ frequency: "weekly", interval: 2, startDate: "2026-11-02" })),
|
||||
).toBe("2 haftada bir Pazartesi");
|
||||
expect(describeRecurrence(rule({ frequency: "yearly", startDate: "2026-03-15" }))).toBe(
|
||||
"Her yıl 15 Mart",
|
||||
);
|
||||
expect(describeRecurrence(rule({ frequency: "daily" }))).toBe("Her gün");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user