Two things, one of them not what it looked like. An organizer fixture was built from a real, routable address. Every other fixture in the codebase uses example.org or example.com, and this repository is public, so that one was a personal address sitting in public source for no reason -- the test asserts roles and participation status and never reads either value. It is [email protected] now. The names were wrong in the other direction. Three fixtures across two files said "John Ellis", which is not the maintainer's name; it is John Coffey. Being a name rather than a routable address, it leaked nothing, but it was simply incorrect, and incorrect in the sort of place nobody rereads. The address and the name are separate questions and got separate answers: the address is fictional because it is an address, and the name is real because it is right. A message from [email protected] signed John Coffey is exactly what these tests mean. Found while checking, at the maintainer's prompting, whether the repo leaked anything about the host it runs on. It does not -- the nginx and deploy files here are the generic examples they claim to be, and the real ones live in a private repository.
59 lines
3.2 KiB
TypeScript
59 lines
3.2 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { participantAddresses, participantEmail, isAttendee, eventRule, makeParticipant } from "@/store/calendar";
|
|
import type { CalendarEvent, JSCalendarParticipant } from "@/jmap/types";
|
|
|
|
/**
|
|
* Stalwart 0.16.19 and RFC 8984 disagree about where a participant's address
|
|
* lives. Sent the RFC's way, Stalwart keeps the event and drops the participant
|
|
* map without a word — guests vanished and no invitation was ever sent (#26).
|
|
* Shapes below are what a live 0.16.19 returned.
|
|
*/
|
|
const p = (o: Partial<JSCalendarParticipant>): JSCalendarParticipant => ({ roles: {}, ...o });
|
|
const ev = (o: Partial<CalendarEvent>): CalendarEvent => ({ id: "e1", "@type": "Event", uid: "u1", calendarIds: { c1: true }, start: "2030-01-01T10:00:00", ...o } as CalendarEvent);
|
|
|
|
describe("participant addresses", () => {
|
|
it("reads Stalwart's calendarAddress", () => {
|
|
expect(participantEmail(p({ calendarAddress: "mailto:[email protected]" }))).toBe("[email protected]");
|
|
});
|
|
it("still reads the RFC 8984 spellings, for events written by other clients", () => {
|
|
expect(participantEmail(p({ sendTo: { imip: "mailto:[email protected]" } }))).toBe("[email protected]");
|
|
expect(participantEmail(p({ email: "[email protected]" }))).toBe("[email protected]");
|
|
expect(participantAddresses(p({ calendarAddress: "mailto:[email protected]", email: "[email protected]" }))).toEqual(["mailto:[email protected]", "mailto:[email protected]"]);
|
|
});
|
|
it("has no address to offer when the participant carries none", () => {
|
|
expect(participantEmail(p({ name: "Nameless" }))).toBe("");
|
|
});
|
|
it("counts a participant as attending under either role name", () => {
|
|
expect(isAttendee(p({ roles: { attendee: true } }))).toBe(true);
|
|
expect(isAttendee(p({ roles: { required: true } }))).toBe(true); // what Stalwart writes for REQ-PARTICIPANT
|
|
expect(isAttendee(p({ roles: { optional: true } }))).toBe(true);
|
|
expect(isAttendee(p({ roles: { owner: true } }))).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("makeParticipant", () => {
|
|
it("addresses a guest the way Stalwart stores them", () => {
|
|
const guest = makeParticipant("[email protected]", "Guest", "attendee");
|
|
expect(guest.calendarAddress).toBe("mailto:[email protected]");
|
|
expect(guest.sendTo).toBeUndefined();
|
|
expect(guest.roles).toEqual({ attendee: true, required: true });
|
|
expect(guest.participationStatus).toBe("needs-action");
|
|
expect(guest.expectReply).toBe(true);
|
|
});
|
|
it("marks the organizer as owner and keeps a status already given", () => {
|
|
const me = makeParticipant("[email protected]", "John Coffey", "owner");
|
|
expect(me.roles).toEqual({ owner: true, attendee: true });
|
|
expect(me.participationStatus).toBe("accepted");
|
|
expect(me.expectReply).toBe(false);
|
|
expect(makeParticipant("[email protected]", null, "attendee", "declined").participationStatus).toBe("declined");
|
|
});
|
|
});
|
|
|
|
describe("eventRule", () => {
|
|
it("reads Stalwart's singular rule and the RFC's array", () => {
|
|
expect(eventRule(ev({ recurrenceRule: { "@type": "RecurrenceRule", frequency: "weekly" } }))?.frequency).toBe("weekly");
|
|
expect(eventRule(ev({ recurrenceRules: [{ "@type": "RecurrenceRule", frequency: "daily" }] }))?.frequency).toBe("daily");
|
|
expect(eventRule(ev({}))).toBeUndefined();
|
|
});
|
|
});
|