import { describe, expect, it } from "vitest";
import { createDavFixture, davRequest } from "@tests/worker/helpers/dav";
import { fetchWorker } from "@tests/worker/helpers/http";
import { withEnvBinding } from "@tests/worker/helpers/env";
import { event, reportBody, uid } from "./helpers";
describe("CalDAV report limits and origins", () => {
it("matches category text filters and expands recurring calendar-data", async () => {
const fixture = await createDavFixture(["caldav.full"]);
const categoryUid = uid();
expect(
await fetchWorker(
davRequest(fixture, "/calendars/default/category.ics", {
method: "PUT",
body: event({ uid: categoryUid, summary: "Categorized", categories: ["Focus", "Team"] }),
}),
),
).toMatchObject({ status: 201 });
const categoryQuery = await fetchWorker(
davRequest(fixture, "/calendars/default/", {
method: "REPORT",
headers: { "content-type": "application/xml", depth: "1" },
body: reportBody(
"calendar-query",
'focus',
),
}),
);
expect(categoryQuery.status).toBe(207);
expect(await categoryQuery.text()).toContain("/calendars/default/category.ics");
const recurrenceUid = uid();
const recurring = [
"BEGIN:VCALENDAR",
"VERSION:2.0",
"PRODID:-//dab//tests//EN",
"BEGIN:VEVENT",
`UID:${recurrenceUid}`,
"DTSTAMP:20260101T000000Z",
"SUMMARY:Daily",
"DTSTART:20260521T120000Z",
"DTEND:20260521T130000Z",
"RRULE:FREQ=DAILY;COUNT=3",
"END:VEVENT",
"BEGIN:VEVENT",
`UID:${recurrenceUid}`,
"DTSTAMP:20260101T000000Z",
"RECURRENCE-ID:20260522T120000Z",
"SUMMARY:Moved Daily",
"DTSTART:20260522T150000Z",
"DTEND:20260522T160000Z",
"END:VEVENT",
"END:VCALENDAR",
"",
].join("\r\n");
expect(
await fetchWorker(
davRequest(fixture, "/calendars/default/recurring.ics", {
method: "PUT",
body: recurring,
}),
),
).toMatchObject({ status: 201 });
const recurrenceQuery = await fetchWorker(
davRequest(fixture, "/calendars/default/", {
method: "REPORT",
headers: { "content-type": "application/xml", depth: "1" },
body: reportBody(
"calendar-query",
'',
),
}),
);
expect(recurrenceQuery.status).toBe(207);
const recurrenceXml = await recurrenceQuery.text();
expect(recurrenceXml).toContain("/calendars/default/recurring.ics");
expect(recurrenceXml).toContain("RECURRENCE-ID:20260522T120000Z");
expect(recurrenceXml).toContain("SUMMARY:Moved Daily");
expect(recurrenceXml).not.toContain("RRULE:FREQ=DAILY");
});
it("applies the configured REPORT result limit to calendar-query and calendar-multiget", async () => {
const fixture = await createDavFixture(["caldav.full"]);
const firstName = `limited-a-${crypto.randomUUID()}.ics`;
const secondName = `limited-b-${crypto.randomUUID()}.ics`;
expect(
await fetchWorker(
davRequest(fixture, `/calendars/default/${firstName}`, {
method: "PUT",
body: event({ uid: uid(), summary: "Limited A" }),
}),
),
).toMatchObject({ status: 201 });
expect(
await fetchWorker(
davRequest(fixture, `/calendars/default/${secondName}`, {
method: "PUT",
body: event({ uid: uid(), summary: "Limited B" }),
}),
),
).toMatchObject({ status: 201 });
await withEnvBinding("MAX_REPORT_RESULTS", "1", async () => {
// RFC 4791 7.8: when a calendar-query result set exceeds the configured
// limit, return a DAV:number-of-matches-within-limits precondition error.
const query = await fetchWorker(
davRequest(fixture, "/calendars/default/", {
method: "REPORT",
headers: { "content-type": "application/xml", depth: "1" },
body: reportBody(
"calendar-query",
'',
),
}),
);
expect(query.status).toBe(403);
await expect(query.text()).resolves.toContain("number-of-matches-within-limits");
const multiget = await fetchWorker(
davRequest(fixture, "/calendars/default/", {
method: "REPORT",
headers: { "content-type": "application/xml" },
body: reportBody(
"calendar-multiget",
`/calendars/default/${firstName}/calendars/default/${secondName}`,
),
}),
);
expect(multiget.status).toBe(403);
});
});
it("rejects calendar-multiget absolute hrefs outside the subject origin", async () => {
const fixture = await createDavFixture(["caldav.full"]);
const name = `absolute-origin-${crypto.randomUUID()}.ics`;
const eventUid = uid();
expect(
await fetchWorker(
davRequest(fixture, `/calendars/default/${name}`, {
method: "PUT",
body: event({ uid: eventUid, summary: "Absolute Origin" }),
}),
),
).toMatchObject({ status: 201 });
const multiget = await fetchWorker(
davRequest(fixture, "/calendars/default/", {
method: "REPORT",
headers: { "content-type": "application/xml" },
body: reportBody(
"calendar-multiget",
`https://other.example.test/calendars/default/${name}`,
),
}),
);
expect(multiget.status).toBe(207);
const xml = await multiget.text();
expect(xml).toContain(`https://other.example.test/calendars/default/${name}`);
expect(xml).toContain("HTTP/1.1 404 Not Found");
expect(xml).not.toContain(eventUid);
});
});