117 lines
3.3 KiB
TypeScript
117 lines
3.3 KiB
TypeScript
import assert from "node:assert/strict"
|
||
import { describe, it } from "node:test"
|
||
import { describeRRule, expandOccurrences, parseRRule } from "./agenda-recurrence.ts"
|
||
|
||
const d = (iso: string) => new Date(iso)
|
||
|
||
describe("parseRRule", () => {
|
||
it("parse une règle hebdomadaire avec BYDAY", () => {
|
||
const rule = parseRRule("FREQ=WEEKLY;INTERVAL=2;BYDAY=MO,TH")
|
||
assert.deepEqual(rule, {
|
||
freq: "WEEKLY",
|
||
interval: 2,
|
||
count: undefined,
|
||
until: undefined,
|
||
byday: [1, 4],
|
||
})
|
||
})
|
||
|
||
it("rejette une fréquence inconnue", () => {
|
||
assert.equal(parseRRule("FREQ=HOURLY"), null)
|
||
})
|
||
})
|
||
|
||
describe("expandOccurrences", () => {
|
||
it("développe une règle quotidienne dans la fenêtre", () => {
|
||
const rule = parseRRule("FREQ=DAILY")!
|
||
const out = expandOccurrences(
|
||
d("2026-06-01T10:00:00"),
|
||
rule,
|
||
new Set(),
|
||
d("2026-06-10T00:00:00"),
|
||
d("2026-06-12T23:59:59"),
|
||
)
|
||
assert.deepEqual(out.map((x) => x.getDate()), [10, 11, 12])
|
||
})
|
||
|
||
it("respecte COUNT depuis la première occurrence", () => {
|
||
const rule = parseRRule("FREQ=DAILY;COUNT=5")!
|
||
const out = expandOccurrences(
|
||
d("2026-06-01T10:00:00"),
|
||
rule,
|
||
new Set(),
|
||
d("2026-06-04T00:00:00"),
|
||
d("2026-06-30T23:59:59"),
|
||
)
|
||
// Occurrences 1–5 = 1er au 5 juin ; fenêtre depuis le 4 → 4 et 5 juin.
|
||
assert.deepEqual(out.map((x) => x.getDate()), [4, 5])
|
||
})
|
||
|
||
it("respecte UNTIL", () => {
|
||
const rule = parseRRule("FREQ=WEEKLY;UNTIL=20260615T000000Z")!
|
||
const out = expandOccurrences(
|
||
d("2026-06-01T10:00:00"),
|
||
rule,
|
||
new Set(),
|
||
d("2026-06-01T00:00:00"),
|
||
d("2026-07-31T23:59:59"),
|
||
)
|
||
assert.equal(out.length, 2) // 1er et 8 juin (15 juin 10:00 > UNTIL)
|
||
})
|
||
|
||
it("développe BYDAY hebdomadaire en gardant l'heure", () => {
|
||
const rule = parseRRule("FREQ=WEEKLY;BYDAY=MO,WE")!
|
||
// Lundi 1er juin 2026 à 09:30.
|
||
const out = expandOccurrences(
|
||
d("2026-06-01T09:30:00"),
|
||
rule,
|
||
new Set(),
|
||
d("2026-06-01T00:00:00"),
|
||
d("2026-06-07T23:59:59"),
|
||
)
|
||
assert.deepEqual(
|
||
out.map((x) => [x.getDate(), x.getHours(), x.getMinutes()]),
|
||
[
|
||
[1, 9, 30],
|
||
[3, 9, 30],
|
||
],
|
||
)
|
||
})
|
||
|
||
it("exclut les EXDATE", () => {
|
||
const rule = parseRRule("FREQ=DAILY")!
|
||
const out = expandOccurrences(
|
||
d("2026-06-01T10:00:00"),
|
||
rule,
|
||
new Set([d("2026-06-02T10:00:00").getTime()]),
|
||
d("2026-06-01T00:00:00"),
|
||
d("2026-06-03T23:59:59"),
|
||
)
|
||
assert.deepEqual(out.map((x) => x.getDate()), [1, 3])
|
||
})
|
||
|
||
it("ne produit aucune occurrence avant le début du master", () => {
|
||
const rule = parseRRule("FREQ=WEEKLY;BYDAY=MO,FR")!
|
||
// Master mercredi 3 juin 2026 → seul le vendredi 5 reste cette semaine-là.
|
||
const out = expandOccurrences(
|
||
d("2026-06-03T10:00:00"),
|
||
rule,
|
||
new Set(),
|
||
d("2026-06-01T00:00:00"),
|
||
d("2026-06-07T23:59:59"),
|
||
)
|
||
assert.deepEqual(out.map((x) => x.getDate()), [5])
|
||
})
|
||
})
|
||
|
||
describe("describeRRule", () => {
|
||
it("décrit les règles courantes", () => {
|
||
assert.equal(describeRRule("FREQ=DAILY"), "Tous les jours")
|
||
assert.equal(
|
||
describeRRule("FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR"),
|
||
"Tous les jours ouvrés (lun.–ven.)",
|
||
)
|
||
assert.equal(describeRRule("FREQ=MONTHLY;INTERVAL=3"), "Tous les 3 mois")
|
||
})
|
||
})
|