mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 10:02:05 +00:00
refactor(core): Move execution engine code out of n8n-workflow (no-changelog) (#12147)
This commit is contained in:
committed by
GitHub
parent
73f0c4cca9
commit
5a055ed526
@@ -9,10 +9,8 @@ import {
|
||||
import {
|
||||
getNodeParameters,
|
||||
getNodeHints,
|
||||
isSingleExecution,
|
||||
isSubNodeType,
|
||||
applyDeclarativeNodeOptionParameters,
|
||||
convertNodeToAiTool,
|
||||
} from '@/NodeHelpers';
|
||||
import type { Workflow } from '@/Workflow';
|
||||
|
||||
@@ -3542,34 +3540,6 @@ describe('NodeHelpers', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('isSingleExecution', () => {
|
||||
test('should determine based on node parameters if it would be executed once', () => {
|
||||
expect(isSingleExecution('n8n-nodes-base.code', {})).toEqual(true);
|
||||
expect(isSingleExecution('n8n-nodes-base.code', { mode: 'runOnceForEachItem' })).toEqual(
|
||||
false,
|
||||
);
|
||||
expect(isSingleExecution('n8n-nodes-base.executeWorkflow', {})).toEqual(true);
|
||||
expect(isSingleExecution('n8n-nodes-base.executeWorkflow', { mode: 'each' })).toEqual(false);
|
||||
expect(isSingleExecution('n8n-nodes-base.crateDb', {})).toEqual(true);
|
||||
expect(isSingleExecution('n8n-nodes-base.crateDb', { operation: 'update' })).toEqual(true);
|
||||
expect(isSingleExecution('n8n-nodes-base.timescaleDb', {})).toEqual(true);
|
||||
expect(isSingleExecution('n8n-nodes-base.timescaleDb', { operation: 'update' })).toEqual(
|
||||
true,
|
||||
);
|
||||
expect(isSingleExecution('n8n-nodes-base.microsoftSql', {})).toEqual(true);
|
||||
expect(isSingleExecution('n8n-nodes-base.microsoftSql', { operation: 'update' })).toEqual(
|
||||
true,
|
||||
);
|
||||
expect(isSingleExecution('n8n-nodes-base.microsoftSql', { operation: 'delete' })).toEqual(
|
||||
true,
|
||||
);
|
||||
expect(isSingleExecution('n8n-nodes-base.questDb', {})).toEqual(true);
|
||||
expect(isSingleExecution('n8n-nodes-base.mongoDb', { operation: 'insert' })).toEqual(true);
|
||||
expect(isSingleExecution('n8n-nodes-base.mongoDb', { operation: 'update' })).toEqual(true);
|
||||
expect(isSingleExecution('n8n-nodes-base.redis', {})).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isSubNodeType', () => {
|
||||
const tests: Array<[boolean, Pick<INodeTypeDescription, 'outputs'> | null]> = [
|
||||
[false, null],
|
||||
@@ -3637,177 +3607,4 @@ describe('NodeHelpers', () => {
|
||||
expect(nodeType.description.properties).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('convertNodeToAiTool', () => {
|
||||
let fullNodeWrapper: { description: INodeTypeDescription };
|
||||
|
||||
beforeEach(() => {
|
||||
fullNodeWrapper = {
|
||||
description: {
|
||||
displayName: 'Test Node',
|
||||
name: 'testNode',
|
||||
group: ['test'],
|
||||
description: 'A test node',
|
||||
version: 1,
|
||||
defaults: {},
|
||||
inputs: [NodeConnectionType.Main],
|
||||
outputs: [NodeConnectionType.Main],
|
||||
properties: [],
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
it('should modify the name and displayName correctly', () => {
|
||||
const result = convertNodeToAiTool(fullNodeWrapper);
|
||||
expect(result.description.name).toBe('testNodeTool');
|
||||
expect(result.description.displayName).toBe('Test Node Tool');
|
||||
});
|
||||
|
||||
it('should update inputs and outputs', () => {
|
||||
const result = convertNodeToAiTool(fullNodeWrapper);
|
||||
expect(result.description.inputs).toEqual([]);
|
||||
expect(result.description.outputs).toEqual([NodeConnectionType.AiTool]);
|
||||
});
|
||||
|
||||
it('should remove the usableAsTool property', () => {
|
||||
fullNodeWrapper.description.usableAsTool = true;
|
||||
const result = convertNodeToAiTool(fullNodeWrapper);
|
||||
expect(result.description.usableAsTool).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should add toolDescription property if it doesn't exist", () => {
|
||||
const result = convertNodeToAiTool(fullNodeWrapper);
|
||||
const toolDescriptionProp = result.description.properties.find(
|
||||
(prop) => prop.name === 'toolDescription',
|
||||
);
|
||||
expect(toolDescriptionProp).toBeDefined();
|
||||
expect(toolDescriptionProp?.type).toBe('string');
|
||||
expect(toolDescriptionProp?.default).toBe(fullNodeWrapper.description.description);
|
||||
});
|
||||
|
||||
it('should set codex categories correctly', () => {
|
||||
const result = convertNodeToAiTool(fullNodeWrapper);
|
||||
expect(result.description.codex).toEqual({
|
||||
categories: ['AI'],
|
||||
subcategories: {
|
||||
AI: ['Tools'],
|
||||
Tools: ['Other Tools'],
|
||||
},
|
||||
resources: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should preserve existing properties', () => {
|
||||
const existingProp: INodeProperties = {
|
||||
displayName: 'Existing Prop',
|
||||
name: 'existingProp',
|
||||
type: 'string',
|
||||
default: 'test',
|
||||
};
|
||||
fullNodeWrapper.description.properties = [existingProp];
|
||||
const result = convertNodeToAiTool(fullNodeWrapper);
|
||||
expect(result.description.properties).toHaveLength(3); // Existing prop + toolDescription + notice
|
||||
expect(result.description.properties).toContainEqual(existingProp);
|
||||
});
|
||||
|
||||
it('should handle nodes with resource property', () => {
|
||||
const resourceProp: INodeProperties = {
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
type: 'options',
|
||||
options: [{ name: 'User', value: 'user' }],
|
||||
default: 'user',
|
||||
};
|
||||
fullNodeWrapper.description.properties = [resourceProp];
|
||||
const result = convertNodeToAiTool(fullNodeWrapper);
|
||||
expect(result.description.properties[1].name).toBe('descriptionType');
|
||||
expect(result.description.properties[2].name).toBe('toolDescription');
|
||||
expect(result.description.properties[3]).toEqual(resourceProp);
|
||||
});
|
||||
|
||||
it('should handle nodes with operation property', () => {
|
||||
const operationProp: INodeProperties = {
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
options: [{ name: 'Create', value: 'create' }],
|
||||
default: 'create',
|
||||
};
|
||||
fullNodeWrapper.description.properties = [operationProp];
|
||||
const result = convertNodeToAiTool(fullNodeWrapper);
|
||||
expect(result.description.properties[1].name).toBe('descriptionType');
|
||||
expect(result.description.properties[2].name).toBe('toolDescription');
|
||||
expect(result.description.properties[3]).toEqual(operationProp);
|
||||
});
|
||||
|
||||
it('should handle nodes with both resource and operation properties', () => {
|
||||
const resourceProp: INodeProperties = {
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
type: 'options',
|
||||
options: [{ name: 'User', value: 'user' }],
|
||||
default: 'user',
|
||||
};
|
||||
const operationProp: INodeProperties = {
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
options: [{ name: 'Create', value: 'create' }],
|
||||
default: 'create',
|
||||
};
|
||||
fullNodeWrapper.description.properties = [resourceProp, operationProp];
|
||||
const result = convertNodeToAiTool(fullNodeWrapper);
|
||||
expect(result.description.properties[1].name).toBe('descriptionType');
|
||||
expect(result.description.properties[2].name).toBe('toolDescription');
|
||||
expect(result.description.properties[3]).toEqual(resourceProp);
|
||||
expect(result.description.properties[4]).toEqual(operationProp);
|
||||
});
|
||||
|
||||
it('should handle nodes with empty properties', () => {
|
||||
fullNodeWrapper.description.properties = [];
|
||||
const result = convertNodeToAiTool(fullNodeWrapper);
|
||||
expect(result.description.properties).toHaveLength(2);
|
||||
expect(result.description.properties[1].name).toBe('toolDescription');
|
||||
});
|
||||
|
||||
it('should handle nodes with existing codex property', () => {
|
||||
fullNodeWrapper.description.codex = {
|
||||
categories: ['Existing'],
|
||||
subcategories: {
|
||||
Existing: ['Category'],
|
||||
},
|
||||
resources: {
|
||||
primaryDocumentation: [{ url: 'https://example.com' }],
|
||||
},
|
||||
};
|
||||
const result = convertNodeToAiTool(fullNodeWrapper);
|
||||
expect(result.description.codex).toEqual({
|
||||
categories: ['AI'],
|
||||
subcategories: {
|
||||
AI: ['Tools'],
|
||||
Tools: ['Other Tools'],
|
||||
},
|
||||
resources: {
|
||||
primaryDocumentation: [{ url: 'https://example.com' }],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle nodes with very long names', () => {
|
||||
fullNodeWrapper.description.name = 'veryLongNodeNameThatExceedsNormalLimits'.repeat(10);
|
||||
fullNodeWrapper.description.displayName =
|
||||
'Very Long Node Name That Exceeds Normal Limits'.repeat(10);
|
||||
const result = convertNodeToAiTool(fullNodeWrapper);
|
||||
expect(result.description.name.endsWith('Tool')).toBe(true);
|
||||
expect(result.description.displayName.endsWith('Tool')).toBe(true);
|
||||
});
|
||||
|
||||
it('should handle nodes with special characters in name and displayName', () => {
|
||||
fullNodeWrapper.description.name = 'special@#$%Node';
|
||||
fullNodeWrapper.description.displayName = 'Special @#$% Node';
|
||||
const result = convertNodeToAiTool(fullNodeWrapper);
|
||||
expect(result.description.name).toBe('special@#$%NodeTool');
|
||||
expect(result.description.displayName).toBe('Special @#$% Node Tool');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user