import { describe, expect, it } from "vitest"; import { createDavFixture, davRequest } from "@tests/worker/helpers/dav"; import { fetchWorker } from "@tests/worker/helpers/http"; import { event, uid as calendarUid } from "@tests/worker/protocol/caldav/helpers"; import { uid as addressUid, vcard } from "@tests/worker/protocol/carddav/helpers"; function encoded(segment: string): string { return encodeURIComponent(segment); } describe("DAV browser HTML listings", () => { it("renders scoped root discovery listings", async () => { const fixture = await createDavFixture(["files.readonly"]); const response = await fetchWorker(davRequest(fixture, "/")); expect(response.status).toBe(200); expect(response.headers.get("content-type")).toContain("text/html"); expect(response.headers.get("cache-control")).toBe("no-store"); expect(response.headers.get("content-security-policy")).toContain("default-src 'none'"); const html = await response.text(); expect(html).toContain("WebDAV file storage"); expect(html).toContain("/files/"); expect(html).not.toContain("/calendars/"); expect(html).not.toContain("/addressbooks/"); expect(await fetchWorker(davRequest(fixture, "/calendars/"))).toHaveProperty("status", 403); expect(await fetchWorker(davRequest(fixture, "/addressbooks/"))).toHaveProperty("status", 403); const head = await fetchWorker(davRequest(fixture, "/", { method: "HEAD" })); expect(head.status).toBe(200); expect(head.headers.get("content-type")).toContain("text/html"); await expect(head.text()).resolves.toBe(""); }); it("renders file collection listings and keeps file GET unchanged", async () => { const fixture = await createDavFixture(["files.full"]); const directory = `browser-${crypto.randomUUID()}`; const fileName = `budget & notes-${crypto.randomUUID()}.txt`; const fileHref = `/files/${directory}/${encoded(fileName)}`; expect(await fetchWorker(davRequest(fixture, `/files/${directory}/`, { method: "MKCOL" }))).toHaveProperty( "status", 201, ); expect( await fetchWorker( davRequest(fixture, fileHref, { method: "PUT", headers: { "content-type": "text/plain" }, body: "listing body", }), ), ).toHaveProperty("status", 201); const listing = await fetchWorker(davRequest(fixture, `/files/${directory}/`)); expect(listing.status).toBe(200); expect(listing.headers.get("content-type")).toContain("text/html"); const html = await listing.text(); expect(html).toContain("Parent directory"); expect(html).toContain("budget <Q2> & notes"); expect(html).not.toContain(fileName); const file = await fetchWorker(davRequest(fixture, fileHref)); expect(file.status).toBe(200); expect(file.headers.get("content-type")).toBe("text/plain"); await expect(file.text()).resolves.toBe("listing body"); }); it("renders calendar listings and keeps calendar object GET unchanged", async () => { const fixture = await createDavFixture(["caldav.full"]); const href = "/calendars/default/listing.ics"; const body = event({ uid: calendarUid(), summary: "Planning & Sync" }); expect( await fetchWorker( davRequest(fixture, href, { method: "PUT", headers: { "content-type": "text/calendar; charset=utf-8" }, body, }), ), ).toHaveProperty("status", 201); const home = await fetchWorker(davRequest(fixture, "/calendars/")); expect(home.status).toBe(200); expect(await home.text()).toContain("/calendars/default/"); const collection = await fetchWorker(davRequest(fixture, "/calendars/default/")); expect(collection.status).toBe(200); const html = await collection.text(); expect(html).toContain("listing.ics"); expect(html).toContain("VEVENT - Planning <Q2> & Sync"); const object = await fetchWorker(davRequest(fixture, href)); expect(object.status).toBe(200); expect(object.headers.get("content-type")).toBe("text/calendar; charset=utf-8"); await expect(object.text()).resolves.toBe(body); }); it("renders address book listings and keeps vCard object GET unchanged", async () => { const fixture = await createDavFixture(["carddav.full"]); const href = "/addressbooks/default/listing.vcf"; const body = vcard({ uid: addressUid(), fn: "Alice & Co", email: "alice@example.test" }); expect( await fetchWorker( davRequest(fixture, href, { method: "PUT", headers: { "content-type": "text/vcard; charset=utf-8" }, body, }), ), ).toHaveProperty("status", 201); const home = await fetchWorker(davRequest(fixture, "/addressbooks/")); expect(home.status).toBe(200); expect(await home.text()).toContain("/addressbooks/default/"); const collection = await fetchWorker(davRequest(fixture, "/addressbooks/default/")); expect(collection.status).toBe(200); const html = await collection.text(); expect(html).toContain("listing.vcf"); expect(html).toContain("Alice <Ops> & Co - alice@example.test"); const object = await fetchWorker(davRequest(fixture, href)); expect(object.status).toBe(200); expect(object.headers.get("content-type")).toBe("text/vcard; charset=utf-8"); await expect(object.text()).resolves.toBe(body); }); });