From 13426b2fbd48041825dc4cbdfdcf789dec5f9797 Mon Sep 17 00:00:00 2001 From: Bowl42 Date: Fri, 6 Mar 2026 11:35:04 +0800 Subject: [PATCH] test: add E2E tests for webhook settings (#871) * test: add E2E tests for webhook settings Co-Authored-By: Claude Opus 4.6 * test: verify headers and body fields in webhook roundtrip test Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Claude Opus 4.6 Co-authored-by: Dream Hunter --- e2e/fixtures/wrangler.toml.e2e | 5 ++ e2e/tests/api/webhook-settings.spec.ts | 88 ++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 e2e/tests/api/webhook-settings.spec.ts diff --git a/e2e/fixtures/wrangler.toml.e2e b/e2e/fixtures/wrangler.toml.e2e index 839e3de5..8076222f 100644 --- a/e2e/fixtures/wrangler.toml.e2e +++ b/e2e/fixtures/wrangler.toml.e2e @@ -16,11 +16,16 @@ ENABLE_AUTO_REPLY = true DEFAULT_SEND_BALANCE = 10 ENABLE_ADDRESS_PASSWORD = true DISABLE_ADMIN_PASSWORD_CHECK = true +ENABLE_WEBHOOK = true E2E_TEST_MODE = true SMTP_CONFIG = """ {"test.example.com":{"host":"mailpit","port":1025,"secure":false}} """ +[[kv_namespaces]] +binding = "KV" +id = "e2e-test-kv-00000000-0000-0000-0000-000000000000" + [[d1_databases]] binding = "DB" database_name = "e2e-temp-email" diff --git a/e2e/tests/api/webhook-settings.spec.ts b/e2e/tests/api/webhook-settings.spec.ts new file mode 100644 index 00000000..71d6e466 --- /dev/null +++ b/e2e/tests/api/webhook-settings.spec.ts @@ -0,0 +1,88 @@ +import { test, expect } from '@playwright/test'; +import { + WORKER_URL, + createTestAddress, + seedTestMail, + deleteAddress, +} from '../../fixtures/test-helpers'; + +test.describe('Webhook Settings', () => { + test('get default webhook settings returns empty/disabled', async ({ request }) => { + const { jwt } = await createTestAddress(request, 'webhook-get'); + + try { + const res = await request.get(`${WORKER_URL}/api/webhook/settings`, { + headers: { Authorization: `Bearer ${jwt}` }, + }); + expect(res.ok()).toBe(true); + const settings = await res.json(); + expect(settings.enabled).toBeFalsy(); + expect(settings.url).toBe(''); + } finally { + await deleteAddress(request, jwt); + } + }); + + test('save and retrieve webhook settings', async ({ request }) => { + const { jwt } = await createTestAddress(request, 'webhook-save'); + + try { + // Save webhook settings + const saveRes = await request.post(`${WORKER_URL}/api/webhook/settings`, { + headers: { Authorization: `Bearer ${jwt}` }, + data: { + enabled: true, + url: 'https://example.com/webhook', + method: 'POST', + headers: JSON.stringify({ 'Content-Type': 'application/json' }), + body: JSON.stringify({ from: '${from}', subject: '${subject}' }), + }, + }); + expect(saveRes.ok()).toBe(true); + const saveBody = await saveRes.json(); + expect(saveBody.success).toBe(true); + + // Retrieve and verify + const getRes = await request.get(`${WORKER_URL}/api/webhook/settings`, { + headers: { Authorization: `Bearer ${jwt}` }, + }); + expect(getRes.ok()).toBe(true); + const settings = await getRes.json(); + expect(settings.enabled).toBe(true); + expect(settings.url).toBe('https://example.com/webhook'); + expect(settings.method).toBe('POST'); + expect(settings.headers).toBe(JSON.stringify({ 'Content-Type': 'application/json' })); + expect(settings.body).toBe(JSON.stringify({ from: '${from}', subject: '${subject}' })); + } finally { + await deleteAddress(request, jwt); + } + }); + + test('test webhook with unreachable URL returns error', async ({ request }) => { + const { jwt, address } = await createTestAddress(request, 'webhook-fail'); + + try { + // Seed a mail so the test endpoint has raw data + await seedTestMail(request, address, { + subject: 'Webhook Fail Test', + from: 'sender@test.example.com', + text: 'This webhook should fail', + }); + + // Test webhook with unreachable URL — expect non-2xx response + const testRes = await request.post(`${WORKER_URL}/api/webhook/test`, { + headers: { Authorization: `Bearer ${jwt}` }, + data: { + enabled: true, + url: 'http://unreachable.invalid/webhook', + method: 'POST', + headers: JSON.stringify({ 'Content-Type': 'application/json' }), + body: JSON.stringify({ from: '${from}' }), + }, + }); + expect(testRes.ok()).toBe(false); + } finally { + await deleteAddress(request, jwt); + } + }); +});