mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 18:12:04 +00:00
fix(core): Return correct trigger count for nodes with multiple webhooks (#14300)
Co-authored-by: Danny Martini <danny@n8n.io> Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ <aditya@netroy.in>
This commit is contained in:
@@ -673,10 +673,23 @@ export class ActiveWorkflowManager {
|
||||
const triggerFilter = (nodeType: INodeType) =>
|
||||
!!nodeType.trigger && !nodeType.description.name.includes('manualTrigger');
|
||||
|
||||
// Retrieve unique webhooks as some nodes have multiple webhooks
|
||||
const workflowWebhooks = WebhookHelpers.getWorkflowWebhooks(
|
||||
workflow,
|
||||
additionalData,
|
||||
undefined,
|
||||
true,
|
||||
);
|
||||
|
||||
const uniqueWebhooks = workflowWebhooks.reduce<Set<string>>((acc, webhook) => {
|
||||
acc.add(webhook.node);
|
||||
return acc;
|
||||
}, new Set());
|
||||
|
||||
return (
|
||||
workflow.queryNodes(triggerFilter).length +
|
||||
workflow.getPollNodes().length +
|
||||
WebhookHelpers.getWorkflowWebhooks(workflow, additionalData, undefined, true).length
|
||||
uniqueWebhooks.size
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,20 @@
|
||||
import { Container } from '@n8n/di';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import { Logger } from 'n8n-core';
|
||||
import { FormTrigger } from 'n8n-nodes-base/nodes/Form/FormTrigger.node';
|
||||
import { ScheduleTrigger } from 'n8n-nodes-base/nodes/Schedule/ScheduleTrigger.node';
|
||||
import { NodeApiError, Workflow } from 'n8n-workflow';
|
||||
import type { IWebhookData, IWorkflowBase, WorkflowActivateMode } from 'n8n-workflow';
|
||||
import type {
|
||||
IWebhookData,
|
||||
IWorkflowBase,
|
||||
WorkflowActivateMode,
|
||||
INodeTypeData,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { ActiveExecutions } from '@/active-executions';
|
||||
import { ActiveWorkflowManager } from '@/active-workflow-manager';
|
||||
import type { WebhookEntity } from '@/databases/entities/webhook-entity';
|
||||
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
|
||||
import { ExecutionService } from '@/executions/execution.service';
|
||||
import { ExternalHooks } from '@/external-hooks';
|
||||
import { NodeTypes } from '@/node-types';
|
||||
@@ -43,7 +51,18 @@ beforeAll(async () => {
|
||||
|
||||
activeWorkflowManager = Container.get(ActiveWorkflowManager);
|
||||
|
||||
await utils.initNodeTypes();
|
||||
const nodes: INodeTypeData = {
|
||||
'n8n-nodes-base.scheduleTrigger': {
|
||||
type: new ScheduleTrigger(),
|
||||
sourcePath: '',
|
||||
},
|
||||
'n8n-nodes-base.formTrigger': {
|
||||
type: new FormTrigger(),
|
||||
sourcePath: '',
|
||||
},
|
||||
};
|
||||
|
||||
await utils.initNodeTypes(nodes);
|
||||
|
||||
const owner = await createOwner();
|
||||
createActiveWorkflow = async () => await createWorkflow({ active: true }, owner);
|
||||
@@ -136,6 +155,43 @@ describe('add()', () => {
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test('should count workflow triggers correctly when node has multiple webhooks', async () => {
|
||||
const workflowRepositoryInstance = Container.get(WorkflowRepository);
|
||||
const updateWorkflowTriggerCountSpy = jest.spyOn(
|
||||
workflowRepositoryInstance,
|
||||
'updateWorkflowTriggerCount',
|
||||
);
|
||||
await activeWorkflowManager.init();
|
||||
|
||||
// Mock all of the webhooks
|
||||
const mockWebhooks: IWebhookData[] = [
|
||||
mock<IWebhookData>({ node: 'Form Trigger', httpMethod: 'GET', path: '/webhook-path' }),
|
||||
mock<IWebhookData>({ node: 'Form Trigger', httpMethod: 'POST', path: '/webhook-path' }),
|
||||
];
|
||||
webhookService.getNodeWebhooks.mockReturnValue(mockWebhooks);
|
||||
webhookService.createWebhook.mockReturnValue(
|
||||
mock<WebhookEntity>({ webhookPath: '/webhook-path' }),
|
||||
);
|
||||
|
||||
// Create a workflow which has a form trigger
|
||||
const dbWorkflow = await createWorkflow({
|
||||
nodes: [
|
||||
{
|
||||
id: 'uuid-1',
|
||||
parameters: { path: 'test-webhook-path', options: {} },
|
||||
name: 'Form Trigger',
|
||||
type: 'n8n-nodes-base.formTrigger',
|
||||
typeVersion: 1,
|
||||
position: [500, 300],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await activeWorkflowManager.add(dbWorkflow.id, 'activate');
|
||||
|
||||
expect(updateWorkflowTriggerCountSpy).toHaveBeenCalledWith(dbWorkflow.id, 1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeAll()', () => {
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
import { Ftp } from 'n8n-nodes-base/credentials/Ftp.credentials';
|
||||
import { GithubApi } from 'n8n-nodes-base/credentials/GithubApi.credentials';
|
||||
import { Cron } from 'n8n-nodes-base/nodes/Cron/Cron.node';
|
||||
import { FormTrigger } from 'n8n-nodes-base/nodes/Form/FormTrigger.node';
|
||||
import { ScheduleTrigger } from 'n8n-nodes-base/nodes/Schedule/ScheduleTrigger.node';
|
||||
import { Set } from 'n8n-nodes-base/nodes/Set/Set.node';
|
||||
import { Start } from 'n8n-nodes-base/nodes/Start/Start.node';
|
||||
@@ -67,9 +68,8 @@ export async function initCredentialsTypes(): Promise<void> {
|
||||
/**
|
||||
* Initialize node types.
|
||||
*/
|
||||
export async function initNodeTypes() {
|
||||
ScheduleTrigger.prototype.trigger = async () => ({});
|
||||
const nodes: INodeTypeData = {
|
||||
export async function initNodeTypes(customNodes?: INodeTypeData) {
|
||||
const defaultNodes: INodeTypeData = {
|
||||
'n8n-nodes-base.start': {
|
||||
type: new Start(),
|
||||
sourcePath: '',
|
||||
@@ -86,7 +86,14 @@ export async function initNodeTypes() {
|
||||
type: new ScheduleTrigger(),
|
||||
sourcePath: '',
|
||||
},
|
||||
'n8n-nodes-base.formTrigger': {
|
||||
type: new FormTrigger(),
|
||||
sourcePath: '',
|
||||
},
|
||||
};
|
||||
|
||||
ScheduleTrigger.prototype.trigger = async () => ({});
|
||||
const nodes = customNodes ?? defaultNodes;
|
||||
const loader = mock<DirectoryLoader>();
|
||||
loader.getNode.mockImplementation((nodeType) => {
|
||||
const node = nodes[`n8n-nodes-base.${nodeType}`];
|
||||
|
||||
@@ -47,14 +47,6 @@ function getNodeVersion(Trigger: new () => VersionedNodeType, version?: number)
|
||||
return instance.nodeVersions[version ?? instance.currentVersion];
|
||||
}
|
||||
|
||||
export async function testVersionedTriggerNode(
|
||||
Trigger: new () => VersionedNodeType,
|
||||
version?: number,
|
||||
options: TestTriggerNodeOptions = {},
|
||||
) {
|
||||
return await testTriggerNode(getNodeVersion(Trigger, version), options);
|
||||
}
|
||||
|
||||
export async function testTriggerNode(
|
||||
Trigger: (new () => INodeType) | INodeType,
|
||||
options: TestTriggerNodeOptions = {},
|
||||
|
||||
Reference in New Issue
Block a user