fix: Execute method should be assigned to a Routing node even if it has webhook defined (#13910)

This commit is contained in:
Michael Kret
2025-03-14 10:56:34 +02:00
committed by GitHub
parent 796a58c7e6
commit 3a4247a91c
4 changed files with 86 additions and 12 deletions

View File

@@ -0,0 +1,68 @@
import type { INodeType } from 'n8n-workflow';
import { shouldAssignExecuteMethod } from '../utils';
describe('shouldAssignExecuteMethod', () => {
it('should return true when node has no execute, poll, trigger, webhook (unless declarative), or methods', () => {
const nodeType = {
description: { requestDefaults: {} }, // Declarative node
execute: undefined,
poll: undefined,
trigger: undefined,
webhook: undefined,
methods: undefined,
} as INodeType;
expect(shouldAssignExecuteMethod(nodeType)).toBe(true);
});
it('should return false when node has execute', () => {
const nodeType = {
execute: jest.fn(),
} as unknown as INodeType;
expect(shouldAssignExecuteMethod(nodeType)).toBe(false);
});
it('should return false when node has poll', () => {
const nodeType = {
poll: jest.fn(),
} as unknown as INodeType;
expect(shouldAssignExecuteMethod(nodeType)).toBe(false);
});
it('should return false when node has trigger', () => {
const nodeType = {
trigger: jest.fn(),
} as unknown as INodeType;
expect(shouldAssignExecuteMethod(nodeType)).toBe(false);
});
it('should return false when node has webhook and is not declarative', () => {
const nodeType = {
description: {},
webhook: jest.fn(),
} as unknown as INodeType;
expect(shouldAssignExecuteMethod(nodeType)).toBe(false);
});
it('should return true when node has webhook but is declarative', () => {
const nodeType = {
description: { requestDefaults: {} }, // Declarative node
webhook: jest.fn(),
} as unknown as INodeType;
expect(shouldAssignExecuteMethod(nodeType)).toBe(true);
});
it('should return false when node has methods', () => {
const nodeType = {
methods: {},
} as unknown as INodeType;
expect(shouldAssignExecuteMethod(nodeType)).toBe(false);
});
});

View File

@@ -10,6 +10,7 @@ import { NodeHelpers, UnexpectedError, UserError } from 'n8n-workflow';
import { join, dirname } from 'path';
import { LoadNodesAndCredentials } from './load-nodes-and-credentials';
import { shouldAssignExecuteMethod } from './utils';
@Service()
export class NodeTypes implements INodeTypes {
@@ -55,13 +56,7 @@ export class NodeTypes implements INodeTypes {
throw new UnexpectedError('Node already has a `supplyData` method', { extra: { nodeType } });
}
if (
!versionedNodeType.execute &&
!versionedNodeType.poll &&
!versionedNodeType.trigger &&
!versionedNodeType.webhook &&
!versionedNodeType.methods
) {
if (shouldAssignExecuteMethod(versionedNodeType)) {
versionedNodeType.execute = async function (this: ExecuteContext) {
const routingNode = new RoutingNode(this, versionedNodeType);
const data = await routingNode.runNode();

View File

@@ -1,5 +1,5 @@
import { CliWorkflowOperationError, SubworkflowOperationError } from 'n8n-workflow';
import type { INode } from 'n8n-workflow';
import type { INode, INodeType } from 'n8n-workflow';
import { STARTING_NODES } from '@/constants';
@@ -90,3 +90,18 @@ export function rightDiff<T1, T2>(
export const assertNever = (_value: never) => {};
export const isPositiveInteger = (maybeInt: string) => /^[1-9]\d*$/.test(maybeInt);
/**
* Check if a execute method should be assigned to the node
*/
export const shouldAssignExecuteMethod = (nodeType: INodeType) => {
const isDeclarativeNode = nodeType?.description?.requestDefaults !== undefined;
return (
!nodeType.execute &&
!nodeType.poll &&
!nodeType.trigger &&
(!nodeType.webhook || isDeclarativeNode) &&
!nodeType.methods
);
};