A one-time event opened for editing said "this is a recurring event — changes apply to the whole series", and deleting one offered to delete all occurrences of an event that has exactly one. Three places asked whether an event had a baseEventId and took that for recurrence. It isn't: the calendar loads its range with expandRecurrences, and Stalwart puts a baseEventId on everything it returns that way, a one-off pointing at itself included. The mock never sets the field at all, which is why this only showed up against a real server. They now share isRecurring(), which asks about recurrence rules, and treats a base that is some other event as an occurrence of a series too — so an expanded instance that travels without its rules is still described honestly on the way to being deleted. Fixes #25
28 lines
1.5 KiB
TypeScript
28 lines
1.5 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);
|
|
});
|
|
it("still recognises an occurrence whose base is another event", () => {
|
|
expect(isRecurring(ev({ id: "ev1_2", baseEventId: "ev1" }))).toBe(true);
|
|
});
|
|
it("recognises a series by its recurrence rules", () => {
|
|
expect(isRecurring(ev({ recurrenceRules: [{ "@type": "RecurrenceRule", frequency: "weekly" }] }))).toBe(true);
|
|
expect(isRecurring(ev({ baseEventId: "ev1", recurrenceRules: [{ "@type": "RecurrenceRule", frequency: "daily" }] }))).toBe(true);
|
|
expect(isRecurring(ev({ excludedRecurrenceRules: [{ "@type": "RecurrenceRule", frequency: "monthly" }] }))).toBe(true);
|
|
});
|
|
});
|