aboutsummaryrefslogtreecommitdiff
path: root/test/integrations.test.ts
diff options
context:
space:
mode:
authorElizabeth Hunt <me@liz.coffee>2025-12-15 20:17:22 -0800
committerElizabeth Hunt <me@liz.coffee>2025-12-15 20:19:43 -0800
commit2814d5520623efe5f48c26f639d3ed6cc5f0d8d2 (patch)
tree3fc1af65dac5ed55aceaab7574b22fea32cad86a /test/integrations.test.ts
parent2e41f030f02a336c2e9866d3d56b0494da5a622e (diff)
downloadposthook-2814d5520623efe5f48c26f639d3ed6cc5f0d8d2.tar.gz
posthook-2814d5520623efe5f48c26f639d3ed6cc5f0d8d2.zip
Add email integration
Diffstat (limited to 'test/integrations.test.ts')
-rw-r--r--test/integrations.test.ts144
1 files changed, 143 insertions, 1 deletions
diff --git a/test/integrations.test.ts b/test/integrations.test.ts
index 310945a..72c653d 100644
--- a/test/integrations.test.ts
+++ b/test/integrations.test.ts
@@ -2,7 +2,8 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { verifyHCaptcha } from '../src/integrations/hcaptcha.js';
import { sendNtfyNotification } from '../src/integrations/ntfy.js';
-import type { NtfyConfig, StoredRequest } from '../src/types/index.js';
+import { sendEmailNotification } from '../src/integrations/email.js';
+import type { EmailConfig, NtfyConfig, StoredRequest } from '../src/types/index.js';
describe('verifyHCaptcha', () => {
beforeEach(() => {
@@ -126,3 +127,144 @@ describe('sendNtfyNotification', () => {
expect(result.left().get().message).toBe('ntfy notification failed: Unauthorized');
});
});
+
+describe('sendEmailNotification', () => {
+ beforeEach(() => {
+ vi.mock('nodemailer', () => ({
+ default: {
+ createTransport: vi.fn(() => ({
+ sendMail: vi.fn().mockResolvedValue(undefined),
+ })),
+ },
+ }));
+ });
+
+ afterEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it('is a no-op when not enabled or misconfigured', async () => {
+ const { default: nodemailer } = await import('nodemailer');
+
+ const config: EmailConfig = { enabled: false };
+ const request: StoredRequest = {
+ timestamp: 1,
+ uuid: 'uuid',
+ routeName: 'route1',
+ method: 'POST',
+ headers: {},
+ body: {},
+ };
+
+ const result = await sendEmailNotification(config, request);
+ expect(result.left().present()).toBe(false);
+ expect(nodemailer.createTransport).not.toHaveBeenCalled();
+ });
+
+ it('sends an email with the configured settings', async () => {
+ const { default: nodemailer } = await import('nodemailer');
+ const sendMailMock = vi.fn().mockResolvedValue(undefined);
+ vi.mocked(nodemailer.createTransport).mockReturnValue({
+ sendMail: sendMailMock,
+ } as any);
+
+ const config: EmailConfig = {
+ enabled: true,
+ to: 'admin@example.com',
+ from: 'webhook@example.com',
+ host: 'smtp.example.com',
+ port: 587,
+ secure: true,
+ username: 'user',
+ password: 'pass',
+ subject: 'Test Subject',
+ includeBody: true,
+ includeHeaders: false,
+ };
+ const request: StoredRequest = {
+ timestamp: Date.parse('2020-01-01T00:00:00.000Z'),
+ uuid: 'test-uuid',
+ routeName: 'test-route',
+ method: 'POST',
+ headers: { 'content-type': 'application/json' },
+ body: { test: 'data' },
+ };
+
+ const result = await sendEmailNotification(config, request);
+ expect(result.left().present()).toBe(false);
+
+ expect(nodemailer.createTransport).toHaveBeenCalledWith({
+ host: 'smtp.example.com',
+ port: 587,
+ secure: true,
+ auth: {
+ user: 'user',
+ pass: 'pass',
+ },
+ });
+
+ expect(sendMailMock).toHaveBeenCalledTimes(1);
+ const mailOptions = sendMailMock.mock.calls[0][0];
+ expect(mailOptions.from).toBe('webhook@example.com');
+ expect(mailOptions.to).toBe('admin@example.com');
+ expect(mailOptions.subject).toBe('Test Subject');
+ expect(mailOptions.html).toContain('test-route');
+ expect(mailOptions.html).toContain('POST');
+ expect(mailOptions.html).toContain('2020-01-01T00:00:00.000Z');
+ expect(mailOptions.html).toContain('test-uuid');
+ expect(mailOptions.html).toContain('"test": "data"');
+ });
+
+ it('uses default subject when not configured', async () => {
+ const { default: nodemailer } = await import('nodemailer');
+ const sendMailMock = vi.fn().mockResolvedValue(undefined);
+ vi.mocked(nodemailer.createTransport).mockReturnValue({
+ sendMail: sendMailMock,
+ } as any);
+
+ const config: EmailConfig = {
+ enabled: true,
+ to: 'admin@example.com',
+ from: 'webhook@example.com',
+ };
+ const request: StoredRequest = {
+ timestamp: 1,
+ uuid: 'uuid',
+ routeName: 'my-route',
+ method: 'POST',
+ headers: {},
+ body: {},
+ };
+
+ await sendEmailNotification(config, request);
+
+ const mailOptions = sendMailMock.mock.calls[0][0];
+ expect(mailOptions.subject).toBe('Webhook received: my-route');
+ });
+
+ it('returns an error when email sending fails', async () => {
+ const { default: nodemailer } = await import('nodemailer');
+ const sendMailMock = vi.fn().mockRejectedValue(new Error('SMTP error'));
+ vi.mocked(nodemailer.createTransport).mockReturnValue({
+ sendMail: sendMailMock,
+ } as any);
+
+ const config: EmailConfig = {
+ enabled: true,
+ to: 'admin@example.com',
+ from: 'webhook@example.com',
+ };
+ const request: StoredRequest = {
+ timestamp: 1,
+ uuid: 'uuid',
+ routeName: 'route1',
+ method: 'POST',
+ headers: {},
+ body: {},
+ };
+
+ const result = await sendEmailNotification(config, request);
+ expect(result.left().present()).toBe(true);
+ expect(result.left().get().message).toBe('SMTP error');
+ });
+});