2023-12-28 00:28:12 -08:00
|
|
|
import { mock } from 'jest-mock-extended';
|
2023-12-19 08:32:02 -08:00
|
|
|
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';
|
|
|
|
|
2023-12-28 00:28:12 -08:00
|
|
|
import type { IWorkflowDb, WebhookRegistration, WebhookRequest } from '@/Interfaces';
|
2023-12-19 08:32:02 -08:00
|
|
|
import type {
|
|
|
|
IWebhookData,
|
|
|
|
IWorkflowExecuteAdditionalData,
|
|
|
|
Workflow,
|
|
|
|
WorkflowActivateMode,
|
|
|
|
WorkflowExecuteMode,
|
|
|
|
} from 'n8n-workflow';
|
|
|
|
|
|
|
|
describe('TestWebhooks', () => {
|
2023-12-28 00:28:12 -08:00
|
|
|
const testWebhooks = new TestWebhooks(mock(), mock());
|
2023-12-19 08:32:02 -08:00
|
|
|
|
2023-12-28 00:28:12 -08:00
|
|
|
beforeAll(() => {
|
|
|
|
jest.useFakeTimers();
|
|
|
|
});
|
2023-12-19 08:32:02 -08:00
|
|
|
|
|
|
|
afterEach(() => {
|
2023-12-28 00:28:12 -08:00
|
|
|
testWebhooks.clearRegistrations();
|
2023-12-19 08:32:02 -08:00
|
|
|
});
|
|
|
|
|
2023-12-28 00:28:12 -08:00
|
|
|
const httpMethod = 'GET';
|
|
|
|
const path = uuid();
|
|
|
|
const workflowId = generateNanoId();
|
2023-12-19 08:32:02 -08:00
|
|
|
|
2023-12-28 00:28:12 -08:00
|
|
|
const webhook = mock<IWebhookData>({
|
|
|
|
httpMethod,
|
|
|
|
path,
|
|
|
|
workflowId,
|
|
|
|
});
|
2023-12-19 08:32:02 -08:00
|
|
|
|
2023-12-28 00:28:12 -08:00
|
|
|
describe('needsWebhook()', () => {
|
2023-12-19 08:32:02 -08:00
|
|
|
type NeedsWebhookArgs = [
|
|
|
|
IWorkflowDb,
|
|
|
|
Workflow,
|
|
|
|
IWorkflowExecuteAdditionalData,
|
|
|
|
WorkflowExecuteMode,
|
|
|
|
WorkflowActivateMode,
|
|
|
|
];
|
|
|
|
|
2023-12-28 00:28:12 -08:00
|
|
|
const workflow = mock<Workflow>({ id: workflowId });
|
2023-12-19 08:32:02 -08:00
|
|
|
|
|
|
|
const args: NeedsWebhookArgs = [
|
2023-12-28 00:28:12 -08:00
|
|
|
mock<IWorkflowDb>({ id: workflowId }),
|
2023-12-19 08:32:02 -08:00
|
|
|
workflow,
|
2023-12-28 00:28:12 -08:00
|
|
|
mock<IWorkflowExecuteAdditionalData>(),
|
2023-12-19 08:32:02 -08:00
|
|
|
'manual',
|
|
|
|
'manual',
|
|
|
|
];
|
|
|
|
|
2023-12-28 00:28:12 -08:00
|
|
|
test('should return true and activate webhook if needed', async () => {
|
2023-12-19 08:32:02 -08:00
|
|
|
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');
|
|
|
|
});
|
|
|
|
|
2023-12-28 00:28:12 -08:00
|
|
|
test('should deactivate webhooks on failure to activate', async () => {
|
2023-12-19 08:32:02 -08:00
|
|
|
const msg = 'Failed to add webhook to active webhooks';
|
|
|
|
|
|
|
|
jest.spyOn(WebhookHelpers, 'getWorkflowWebhooks').mockReturnValue([webhook]);
|
|
|
|
jest.spyOn(testWebhooks, 'activateWebhook').mockRejectedValue(new Error(msg));
|
2023-12-28 00:28:12 -08:00
|
|
|
const deactivateWebhooksSpy = jest.spyOn(testWebhooks, 'deactivateWebhooks');
|
2023-12-19 08:32:02 -08:00
|
|
|
|
|
|
|
const needsWebhook = testWebhooks.needsWebhook(...args);
|
|
|
|
|
|
|
|
await expect(needsWebhook).rejects.toThrowError(msg);
|
2023-12-28 00:28:12 -08:00
|
|
|
expect(deactivateWebhooksSpy).toHaveBeenCalledWith(workflow);
|
2023-12-19 08:32:02 -08:00
|
|
|
});
|
|
|
|
|
|
|
|
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([]);
|
|
|
|
|
2023-12-28 00:28:12 -08:00
|
|
|
const promise = testWebhooks.executeWebhook(
|
|
|
|
mock<WebhookRequest>({ params: { path } }),
|
|
|
|
mock(),
|
|
|
|
);
|
2023-12-19 08:32:02 -08:00
|
|
|
|
|
|
|
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([]);
|
|
|
|
|
2023-12-28 00:28:12 -08:00
|
|
|
const registration = mock<WebhookRegistration>({
|
2023-12-19 08:32:02 -08:00
|
|
|
sessionId: 'some-session-id',
|
2023-12-28 00:28:12 -08:00
|
|
|
timeout: mock<NodeJS.Timeout>(),
|
|
|
|
workflowEntity: mock<IWorkflowDb>({}),
|
|
|
|
workflow: mock<Workflow>(),
|
|
|
|
});
|
2023-12-19 08:32:02 -08:00
|
|
|
|
2023-12-28 00:28:12 -08:00
|
|
|
testWebhooks.setRegistration(registration);
|
2023-12-19 08:32:02 -08:00
|
|
|
|
2023-12-28 00:28:12 -08:00
|
|
|
const promise = testWebhooks.executeWebhook(
|
|
|
|
mock<WebhookRequest>({ params: { path } }),
|
|
|
|
mock(),
|
|
|
|
);
|
2023-12-19 08:32:02 -08:00
|
|
|
|
2023-12-28 00:28:12 -08:00
|
|
|
await expect(promise).rejects.toThrowError(NotFoundError);
|
2023-12-19 08:32:02 -08:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|