Files
ihasmail-inbuxa/web/src/store/__tests__/recurrence.test.ts
T
jcoffey-dev 458eb118b4 Ask the recurrenceId, which is the part that survives expansion
Rules alone were still wrong, in the other direction. A live 0.16.19 was
asked to expand a real weekly series: the occurrences come back carrying
no rule at all — only the master has one — and Stalwart spells that
master's rule "recurrenceRule", singular, not the RFC 8984 array ihasmail
looks for. So a genuine occurrence would have read as a one-off, and the
delete dialog would have offered to delete "this event" while deleting
the series.

What an occurrence does carry is a recurrenceId, which a one-off never
has. Master by its rule under either name, occurrence by its
recurrenceId. The tests carry the shapes the live server returned.
2026-08-25 08:18:38 -07:00

34 lines
2.0 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { isRecurring } from "@/store/calendar";
import type { CalendarEvent } from "@/jmap/types";
/**
* `CalendarEvent/query` runs with `expandRecurrences`, and Stalwart puts a
* `baseEventId` on everything it returns that way — one-off events included.
* Treating that as proof of a series told people editing a plain event that
* their changes applied to the whole series, and offered to delete "all
* occurrences" of an event that has exactly one.
*/
const ev = (p: Partial<CalendarEvent>): CalendarEvent => ({ id: "ev1", "@type": "Event", uid: "u1", calendarIds: { c1: true }, start: "2026-08-25T09:00:00", duration: "PT30M", ...p } as CalendarEvent);
describe("isRecurring", () => {
it("does not call a one-off event a series just because it has a baseEventId", () => {
expect(isRecurring(ev({ baseEventId: "ev1" }))).toBe(false);
expect(isRecurring(ev({}))).toBe(false);
// The shape a live 0.16.19 returns for a one-off: an instance id of its own,
// and a base that is a different id. Neither makes it a series.
expect(isRecurring(ev({ id: "eaaaaai", baseEventId: "i" }))).toBe(false);
});
it("recognises a series by its rule, under either name", () => {
expect(isRecurring(ev({ recurrenceRules: [{ "@type": "RecurrenceRule", frequency: "weekly" }] }))).toBe(true);
expect(isRecurring(ev({ excludedRecurrenceRules: [{ "@type": "RecurrenceRule", frequency: "monthly" }] }))).toBe(true);
// Stalwart 0.16 keeps a single rule under the singular name.
expect(isRecurring(ev({ recurrenceRule: { "@type": "RecurrenceRule", frequency: "weekly", count: 3 } }))).toBe(true);
});
it("recognises an occurrence, which arrives with no rule of its own", () => {
// A live 0.16.19 expands a weekly series into instances like this: an id
// per occurrence, a recurrenceId, and no rule attached.
expect(isRecurring(ev({ id: "iaaaaas", recurrenceId: "2030-03-11T10:00:00" }))).toBe(true);
});
});