learning_ai_notes/backend/src/lib/webhook-subscriber.test.ts

80 lines
2.0 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest';
const { dispatchToTargetsMock } = vi.hoisted(() => ({
dispatchToTargetsMock: vi.fn(async () => []),
}));
vi.mock('@bytelyst/webhook-dispatch', () => ({
dispatchToTargets: dispatchToTargetsMock,
}));
import { _resetEventBus, getEventBus } from './event-bus.js';
import {
_resetWebhookSubscriberForTests,
initWebhookSubscriber,
isWebhookSubscriberRunning,
registerWebhookTarget,
stopWebhookSubscriber,
} from './webhook-subscriber.js';
describe('webhook subscriber lifecycle', () => {
beforeEach(() => {
_resetWebhookSubscriberForTests();
_resetEventBus();
dispatchToTargetsMock.mockClear();
});
it('does not subscribe until initialized', async () => {
registerWebhookTarget({
id: 'target-1',
url: 'https://example.com/webhook',
secret: 'secret',
events: ['note.created'],
enabled: true,
});
await getEventBus().emit('note.created', {
noteId: 'note-1',
workspaceId: 'ws-1',
userId: 'user-1',
title: 'Created',
});
expect(isWebhookSubscriberRunning()).toBe(false);
expect(dispatchToTargetsMock).not.toHaveBeenCalled();
});
it('initializes idempotently and unsubscribes on stop', async () => {
registerWebhookTarget({
id: 'target-1',
url: 'https://example.com/webhook',
secret: 'secret',
events: ['note.created'],
enabled: true,
});
initWebhookSubscriber();
initWebhookSubscriber();
expect(isWebhookSubscriberRunning()).toBe(true);
await getEventBus().emit('note.created', {
noteId: 'note-1',
workspaceId: 'ws-1',
userId: 'user-1',
title: 'Created',
});
expect(dispatchToTargetsMock).toHaveBeenCalledTimes(1);
stopWebhookSubscriber();
expect(isWebhookSubscriberRunning()).toBe(false);
await getEventBus().emit('note.created', {
noteId: 'note-2',
workspaceId: 'ws-1',
userId: 'user-1',
title: 'Created again',
});
expect(dispatchToTargetsMock).toHaveBeenCalledTimes(1);
});
});