diff --git a/src/application/email-processor.test.ts b/src/application/email-processor.test.ts index 66dffc1..d4b17bf 100644 --- a/src/application/email-processor.test.ts +++ b/src/application/email-processor.test.ts @@ -859,6 +859,28 @@ describe("processEmail — confirmation detection", () => { ); }); + it("marks a plain-text confirmation email and raises pendingConfirmation", async () => { + const result = await processEmail( + makeInput({ + subject: "Confirm your subscription", + content: + "Please confirm your subscription. Click here: https://example.com/confirm?token=xyz to verify your email.", + }), + env as any, + ); + + expect(result.ok).toBe(true); + + const metadata = await env.EMAIL_STORAGE.get( + `feed:${VALID_FEED_ID}:metadata`, + "json", + ); + expect(metadata.pendingConfirmation).toBe(true); + expect(metadata.emails[0].confirmation?.links[0]).toBe( + "https://example.com/confirm?token=xyz", + ); + }); + it("does not mark a regular newsletter as a confirmation", async () => { const result = await processEmail( makeInput({ diff --git a/src/routes/admin.test.ts b/src/routes/admin.test.ts index 636b4e6..2f3164f 100644 --- a/src/routes/admin.test.ts +++ b/src/routes/admin.test.ts @@ -1341,5 +1341,100 @@ describe("Admin Routes", () => { const body = await res.text(); expect(body).toContain("pill-confirmation"); }); + + it("dashboard table view shows pill-confirmation for feeds with pendingConfirmation", async () => { + const authCookie = await loginAndGetCookie(); + const repo = FeedRepository.from(mockEnv as unknown as Env); + + // Create feed aggregate with a confirmation email — same seeding as list view test + const feedId = FeedId.generate(); + const mailboxId = MailboxId.unchecked("confirm.table.05"); + const feed = Feed.create( + feedId, + { + title: "Dashboard Confirm Feed Table", + language: "en", + allowedSenders: [], + blockedSenders: [], + }, + { mailboxId }, + ); + await repo.save(feed); + + const emailKey = repo.newEmailKey(feedId); + await repo.putEmail(emailKey, { + subject: "Confirm your subscription", + from: "newsletter@example.com", + content: "

Click to confirm

", + receivedAt: Date.now(), + headers: {}, + }); + + feed.ingest( + { + key: emailKey, + subject: "Confirm your subscription", + receivedAt: Date.now(), + confirmation: { links: ["https://x/confirm"] }, + }, + { maxBytes: 1_000_000 }, + ); + await repo.saveMetadata(feed); + + const res = await request("/admin?view=table", { + headers: { Cookie: authCookie }, + }); + expect(res.status).toBe(200); + const body = await res.text(); + expect(body).toContain("pill-confirmation"); + }); + + it("feed emails page shows confirmation-banner when pendingConfirmation is true", async () => { + const authCookie = await loginAndGetCookie(); + const repo = FeedRepository.from(mockEnv as unknown as Env); + + // Seed a feed with a confirmation email so pendingConfirmation is raised + const feedId = FeedId.generate(); + const mailboxId = MailboxId.unchecked("confirm.emails.06"); + const feed = Feed.create( + feedId, + { + title: "Emails Page Confirm Feed", + language: "en", + allowedSenders: [], + blockedSenders: [], + }, + { mailboxId }, + ); + await repo.save(feed); + + const emailKey = repo.newEmailKey(feedId); + await repo.putEmail(emailKey, { + subject: "Confirm subscription", + from: "newsletter@example.com", + content: "

Click to confirm

", + receivedAt: Date.now(), + headers: {}, + }); + + feed.ingest( + { + key: emailKey, + subject: "Confirm subscription", + receivedAt: Date.now(), + confirmation: { links: ["https://example.com/confirm?t=6"] }, + }, + { maxBytes: 10_000_000 }, + ); + await repo.saveMetadata(feed); + + const res = await request(`/admin/feeds/${feedId.value}/emails`, { + headers: { Cookie: authCookie }, + }); + expect(res.status).toBe(200); + const body = await res.text(); + expect(body).toContain("confirmation-banner"); + expect(body).toContain("confirmation-dismiss"); + }); }); });