n8n/packages/cli/test/unit/TestWebhooks.test.ts
Iván Ovejero 639afcd7a5
refactor(core): Simplify state in test webhooks (no-changelog) (#8155)
This PR simplifies state in test webhooks so that it can be cached
easily. Caching this state will allow us to start using Redis for manual
webhooks, to support manual webhooks to work in multi-main setup.

- [x] Convert `workflowWebhooks` to a getter - no need to optimize for
deactivation
- [x] Remove array from value in `TestWebhooks.webhookUrls`
- [x] Consolidate `webhookUrls` and `registeredWebhooks`
2023-12-28 09:28:12 +01:00

126 lines
3.8 KiB
TypeScript

import { mock } from 'jest-mock-extended';
import { TestWebhooks } from '@/TestWebhooks';
import { WebhookNotFoundError } from '@/errors/response-errors/webhook-not-found.error';
import { v4 as uuid } from 'uuid';
import { generateNanoId } from '@/databases/utils/generators';
import { NotFoundError } from '@/errors/response-errors/not-found.error';
import * as WebhookHelpers from '@/WebhookHelpers';
import type { IWorkflowDb, WebhookRegistration, WebhookRequest } from '@/Interfaces';
import type {
IWebhookData,
IWorkflowExecuteAdditionalData,
Workflow,
WorkflowActivateMode,
WorkflowExecuteMode,
} from 'n8n-workflow';
describe('TestWebhooks', () => {
const testWebhooks = new TestWebhooks(mock(), mock());
beforeAll(() => {
jest.useFakeTimers();
});
afterEach(() => {
testWebhooks.clearRegistrations();
});
const httpMethod = 'GET';
const path = uuid();
const workflowId = generateNanoId();
const webhook = mock<IWebhookData>({
httpMethod,
path,
workflowId,
});
describe('needsWebhook()', () => {
type NeedsWebhookArgs = [
IWorkflowDb,
Workflow,
IWorkflowExecuteAdditionalData,
WorkflowExecuteMode,
WorkflowActivateMode,
];
const workflow = mock<Workflow>({ id: workflowId });
const args: NeedsWebhookArgs = [
mock<IWorkflowDb>({ id: workflowId }),
workflow,
mock<IWorkflowExecuteAdditionalData>(),
'manual',
'manual',
];
test('should return true and activate webhook if needed', async () => {
jest.spyOn(WebhookHelpers, 'getWorkflowWebhooks').mockReturnValue([webhook]);
const activateWebhookSpy = jest.spyOn(testWebhooks, 'activateWebhook');
const needsWebhook = await testWebhooks.needsWebhook(...args);
expect(needsWebhook).toBe(true);
expect(activateWebhookSpy).toHaveBeenCalledWith(workflow, webhook, 'manual', 'manual');
});
test('should deactivate webhooks on failure to activate', async () => {
const msg = 'Failed to add webhook to active webhooks';
jest.spyOn(WebhookHelpers, 'getWorkflowWebhooks').mockReturnValue([webhook]);
jest.spyOn(testWebhooks, 'activateWebhook').mockRejectedValue(new Error(msg));
const deactivateWebhooksSpy = jest.spyOn(testWebhooks, 'deactivateWebhooks');
const needsWebhook = testWebhooks.needsWebhook(...args);
await expect(needsWebhook).rejects.toThrowError(msg);
expect(deactivateWebhooksSpy).toHaveBeenCalledWith(workflow);
});
test('should return false if no webhook to start workflow', async () => {
webhook.webhookDescription.restartWebhook = true;
jest.spyOn(WebhookHelpers, 'getWorkflowWebhooks').mockReturnValue([webhook]);
const result = await testWebhooks.needsWebhook(...args);
expect(result).toBe(false);
});
});
describe('executeWebhook()', () => {
test('should throw if webhook is not registered', async () => {
jest.spyOn(testWebhooks, 'getActiveWebhook').mockReturnValue(webhook);
jest.spyOn(testWebhooks, 'getWebhookMethods').mockResolvedValue([]);
const promise = testWebhooks.executeWebhook(
mock<WebhookRequest>({ params: { path } }),
mock(),
);
await expect(promise).rejects.toThrowError(WebhookNotFoundError);
});
test('should throw if webhook node is registered but missing from workflow', async () => {
jest.spyOn(testWebhooks, 'getActiveWebhook').mockReturnValue(webhook);
jest.spyOn(testWebhooks, 'getWebhookMethods').mockResolvedValue([]);
const registration = mock<WebhookRegistration>({
sessionId: 'some-session-id',
timeout: mock<NodeJS.Timeout>(),
workflowEntity: mock<IWorkflowDb>({}),
workflow: mock<Workflow>(),
});
testWebhooks.setRegistration(registration);
const promise = testWebhooks.executeWebhook(
mock<WebhookRequest>({ params: { path } }),
mock(),
);
await expect(promise).rejects.toThrowError(NotFoundError);
});
});
});