From 42de0f831540b07fae4e7065ef89775901df2353 Mon Sep 17 00:00:00 2001 From: saltbo Date: Mon, 27 Apr 2026 21:49:26 -0400 Subject: [PATCH] test(email): cover cloudflare fallback branches --- .../routes/email-config.integration.test.ts | 13 ++++ server/services/email.integration.test.ts | 60 ++++++++++++++++++- 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/server/routes/email-config.integration.test.ts b/server/routes/email-config.integration.test.ts index 93bbd714..74fab951 100644 --- a/server/routes/email-config.integration.test.ts +++ b/server/routes/email-config.integration.test.ts @@ -85,6 +85,19 @@ describe('Admin Email Config API — GET', () => { expect(body).toEqual({ enabled: false, provider: null }) }) + it('returns enabled with null provider when email is enabled but sender/provider are incomplete', async () => { + const { app, db } = await createTestApp() + const headers = await adminHeaders(app) + await db.insert(schema.systemOptions).values([{ key: 'email_enabled', value: 'true' }]) + + const res = await app.request('/api/admin/email-config', { headers }) + expect(res.status).toBe(200) + await expect(res.json()).resolves.toEqual({ + enabled: true, + provider: null, + }) + }) + it('returns masked SMTP config after SMTP config is saved', async () => { const { app, db } = await createTestApp() const headers = await adminHeaders(app) diff --git a/server/services/email.integration.test.ts b/server/services/email.integration.test.ts index a5fa77cf..7dc534ea 100644 --- a/server/services/email.integration.test.ts +++ b/server/services/email.integration.test.ts @@ -2,7 +2,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' import * as schema from '../db/schema.js' import type { Platform } from '../platform/interface' import { createTestApp } from '../test/setup.js' -import { getEmailConfig, isEmailConfigured, sendEmail } from './email.js' +import { getEmailConfig, getEmailSettings, isEmailConfigured, sendEmail } from './email.js' const sendMailMock = vi.fn() @@ -122,6 +122,21 @@ describe('getEmailConfig', () => { await expect(getEmailConfig(db)).rejects.toThrow('Unknown email provider: unknown') }) + it('throws when cloudflare provider is selected without EMAIL binding', async () => { + const { db } = await createTestApp() + await db.insert(schema.systemOptions).values([ + { key: 'email_provider', value: 'cloudflare' }, + { key: 'email_from', value: 'no-reply@zpan.space' }, + ]) + const platform = { + db, + getEnv: () => undefined, + getBinding: (_key: string) => undefined as T | undefined, + } satisfies Platform + + await expect(getEmailConfig(platform)).rejects.toThrow('Cloudflare email binding "EMAIL" is not configured') + }) + it('returns Cloudflare config when provider is cloudflare and binding is present', async () => { const { db } = await createTestApp() await db.insert(schema.systemOptions).values([ @@ -303,4 +318,47 @@ describe('sendEmail — Cloudflare provider', () => { 'Email is disabled', ) }) + + it('returns enabled settings with null config when sender is missing', async () => { + const { db } = await createTestApp() + await db.insert(schema.systemOptions).values([ + { key: 'email_enabled', value: 'true' }, + { key: 'email_provider', value: 'smtp' }, + ]) + + await expect(getEmailSettings(db)).resolves.toEqual({ + enabled: true, + config: null, + }) + }) + + it('prefers explicit text for Cloudflare send()', async () => { + const { db } = await createTestApp() + const sendMock = vi.fn().mockResolvedValue({ messageId: 'msg_123' }) + await db.insert(schema.systemOptions).values([ + { key: 'email_enabled', value: 'true' }, + { key: 'email_provider', value: 'cloudflare' }, + { key: 'email_from', value: 'no-reply@zpan.space' }, + ]) + const platform = { + db, + getEnv: () => undefined, + getBinding: (key: string) => (key === 'EMAIL' ? ({ send: sendMock } as T) : undefined), + } satisfies Platform + + await sendEmail(platform, { + to: 'user@example.com', + subject: 'Hello', + html: '

Hi there

', + text: 'Plain text body', + }) + + expect(sendMock).toHaveBeenCalledWith({ + to: 'user@example.com', + from: 'no-reply@zpan.space', + subject: 'Hello', + html: '

Hi there

', + text: 'Plain text body', + }) + }) })