File
Blob: tests/worker/queues/page-projection.workers.test.ts
| 1 | import { env } from "cloudflare:workers"; |
| 2 | import { ulid } from "ulid"; |
| 3 | import { beforeEach, describe, expect, it } from "vitest"; |
| 4 | |
| 5 | import { handlePageProjection } from "@/worker/queues/page-projection"; |
| 6 | import { buildSiteR2ObjectKey, readSiteR2 } from "@/worker/sites/cache"; |
| 7 | import { resetD1Tables } from "@tests/worker/helpers/db"; |
| 8 | import { buildYjsDocBytes, seedDocSyncSnapshot } from "@tests/worker/helpers/do"; |
| 9 | import { seedPage, seedUser, seedWorkspace } from "@tests/worker/helpers/seeds"; |
| 10 | |
| 11 | async function clearSitesBucket(): Promise<void> { |
| 12 | const listing = await env.SITES.list(); |
| 13 | await Promise.all(listing.objects.map((object) => env.SITES.delete(object.key))); |
| 14 | } |
| 15 | |
| 16 | describe("handlePageProjection", () => { |
| 17 | beforeEach(async () => { |
| 18 | await resetD1Tables(); |
| 19 | await clearSitesBucket(); |
| 20 | }); |
| 21 | |
| 22 | it("returns retry when the page is not yet visible in D1", async () => { |
| 23 | await expect(handlePageProjection(ulid(), env)).resolves.toEqual({ kind: "retry", delaySeconds: 2 }); |
| 24 | }); |
| 25 | |
| 26 | it("projects a doc snapshot into the Sites R2 envelope", async () => { |
| 27 | const owner = await seedUser(); |
| 28 | const ws = await seedWorkspace({ owner_id: owner.id }); |
| 29 | const page = await seedPage({ workspace_id: ws.id, created_by: owner.id, title: "Projected" }); |
| 30 | await seedDocSyncSnapshot(page.id, buildYjsDocBytes("Projected", "Projected body text")); |
| 31 | |
| 32 | await expect(handlePageProjection(page.id, env)).resolves.toEqual({ kind: "ok" }); |
| 33 | |
| 34 | const r2 = await readSiteR2(env, ws.id, page.id, page.updated_at); |
| 35 | expect(r2?.fresh).toBe(true); |
| 36 | expect(r2?.envelope?.updatedAt).toBe(page.updated_at); |
| 37 | expect(JSON.stringify(r2?.envelope?.content)).toContain("Projected body text"); |
| 38 | expect(r2?.envelope?.metrics).toEqual({ words: 3, characters: 19 }); |
| 39 | }); |
| 40 | |
| 41 | it("writes an empty envelope when a doc snapshot is missing", async () => { |
| 42 | const owner = await seedUser(); |
| 43 | const ws = await seedWorkspace({ owner_id: owner.id }); |
| 44 | const page = await seedPage({ workspace_id: ws.id, created_by: owner.id, title: "Empty" }); |
| 45 | |
| 46 | await expect(handlePageProjection(page.id, env)).resolves.toEqual({ kind: "ok" }); |
| 47 | |
| 48 | const r2 = await readSiteR2(env, ws.id, page.id, page.updated_at); |
| 49 | expect(r2?.fresh).toBe(true); |
| 50 | expect(r2?.envelope).toEqual({ |
| 51 | content: { type: "doc", content: [] }, |
| 52 | metrics: { words: 0, characters: 0 }, |
| 53 | updatedAt: page.updated_at, |
| 54 | }); |
| 55 | }); |
| 56 | |
| 57 | it("skips canvas pages", async () => { |
| 58 | const owner = await seedUser(); |
| 59 | const ws = await seedWorkspace({ owner_id: owner.id }); |
| 60 | const canvas = await seedPage({ workspace_id: ws.id, created_by: owner.id, kind: "canvas", title: "Canvas" }); |
| 61 | |
| 62 | await expect(handlePageProjection(canvas.id, env)).resolves.toEqual({ kind: "ok" }); |
| 63 | await expect(env.SITES.get(buildSiteR2ObjectKey(ws.id, canvas.id))).resolves.toBeNull(); |
| 64 | }); |
| 65 | }); |