mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-16 17:46:45 +00:00
168 lines
4.9 KiB
TypeScript
168 lines
4.9 KiB
TypeScript
import type { FromAIOverride, OverrideContext } from './fromAIOverrideUtils';
|
|
import {
|
|
buildValueFromOverride,
|
|
fromAIExtraProps,
|
|
isFromAIOverrideValue,
|
|
makeOverrideValue,
|
|
parseOverrides,
|
|
} from './fromAIOverrideUtils';
|
|
import type { INodeTypeDescription } from 'n8n-workflow';
|
|
|
|
const DISPLAY_NAME = 'aDisplayName';
|
|
const PARAMETER_NAME = 'aName';
|
|
|
|
const makeContext = (value: string, path?: string): OverrideContext => ({
|
|
parameter: {
|
|
name: PARAMETER_NAME,
|
|
displayName: DISPLAY_NAME,
|
|
type: 'string',
|
|
},
|
|
value,
|
|
path: path ?? `parameters.${PARAMETER_NAME}`,
|
|
});
|
|
|
|
const MOCK_NODE_TYPE_MIXIN = {
|
|
version: 0,
|
|
defaults: {},
|
|
inputs: [],
|
|
outputs: [],
|
|
properties: [],
|
|
displayName: '',
|
|
group: [],
|
|
description: '',
|
|
};
|
|
|
|
const AI_NODE_TYPE: INodeTypeDescription = {
|
|
name: 'AN_AI_NODE_TYPE',
|
|
codex: {
|
|
categories: ['AI'],
|
|
subcategories: {
|
|
AI: ['Tools'],
|
|
},
|
|
},
|
|
...MOCK_NODE_TYPE_MIXIN,
|
|
};
|
|
|
|
const AI_DENYLIST_NODE_TYPE: INodeTypeDescription = {
|
|
name: 'toolCode',
|
|
codex: {
|
|
categories: ['AI'],
|
|
subcategories: {
|
|
AI: ['Tools'],
|
|
},
|
|
},
|
|
...MOCK_NODE_TYPE_MIXIN,
|
|
};
|
|
|
|
const NON_AI_NODE_TYPE: INodeTypeDescription = {
|
|
name: 'AN_NOT_AI_NODE_TYPE',
|
|
...MOCK_NODE_TYPE_MIXIN,
|
|
};
|
|
|
|
describe('makeOverrideValue', () => {
|
|
test.each<[string, ...Parameters<typeof makeOverrideValue>]>([
|
|
['null nodeType', makeContext(''), null],
|
|
['non-ai node type', makeContext(''), NON_AI_NODE_TYPE],
|
|
['ai node type on denylist', makeContext(''), AI_DENYLIST_NODE_TYPE],
|
|
])('should not create an override for %s', (_name, context, nodeType) => {
|
|
expect(makeOverrideValue(context, nodeType)).toBeNull();
|
|
});
|
|
|
|
it('should create an fromAI override', () => {
|
|
const result = makeOverrideValue(
|
|
makeContext(`={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('${DISPLAY_NAME}') }}`),
|
|
AI_NODE_TYPE,
|
|
);
|
|
|
|
expect(result).not.toBeNull();
|
|
expect(result?.type).toEqual('fromAI');
|
|
});
|
|
|
|
it('parses existing fromAI overrides', () => {
|
|
const description = 'a description';
|
|
const result = makeOverrideValue(
|
|
makeContext(
|
|
`={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('${DISPLAY_NAME}', \`${description}\`) }}`,
|
|
),
|
|
AI_NODE_TYPE,
|
|
);
|
|
|
|
expect(result).toBeDefined();
|
|
expect(result?.extraPropValues.description).toEqual(description);
|
|
});
|
|
|
|
it('parses an existing fromAI override with default values without adding extraPropValue entry', () => {
|
|
const result = makeOverrideValue(
|
|
makeContext("={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('aName', ``) }}"),
|
|
AI_NODE_TYPE,
|
|
);
|
|
|
|
expect(result).toBeDefined();
|
|
expect(result?.extraPropValues.description).not.toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe('FromAiOverride', () => {
|
|
it('correctly identifies override values', () => {
|
|
expect(isFromAIOverrideValue('={{ $fromAI() }}')).toBe(false);
|
|
expect(isFromAIOverrideValue('={{ /*n8n-auto-generated-fromAI-override*/ $fromAI() }}')).toBe(
|
|
true,
|
|
);
|
|
});
|
|
|
|
it('should parseOverrides as expected', () => {
|
|
expect(parseOverrides("={{ $fromAI('aKey' }}")).toBeNull();
|
|
expect(parseOverrides("={{ $fromAI('aKey') }}")).toEqual({
|
|
description: undefined,
|
|
});
|
|
expect(parseOverrides("={{ $fromAI('aKey', `a description`) }}")).toEqual({
|
|
description: 'a description',
|
|
});
|
|
expect(parseOverrides("={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('aKey') }}")).toEqual(
|
|
{ description: undefined },
|
|
);
|
|
expect(
|
|
parseOverrides(
|
|
"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('aKey', `a description`) }}",
|
|
),
|
|
).toEqual({
|
|
description: 'a description',
|
|
});
|
|
});
|
|
|
|
test.each<[string, string, string]>([
|
|
['none', '$fromAI("a", `b`)', 'b'],
|
|
['a simple case of', '$fromAI("a", `\\``)', '`'],
|
|
// this is a bug in the current implementation
|
|
// see related comments in the main file
|
|
// We try to use different quote characters where possible
|
|
['a complex case of', '$fromAI("a", `a \\` \\\\\\``)', 'a ` `'],
|
|
])('should handle %s backtick escaping ', (_name, value, expected) => {
|
|
expect(parseOverrides(value)).toEqual({ description: expected });
|
|
});
|
|
|
|
it('should build a value from an override and carry over modification', () => {
|
|
const override: FromAIOverride = {
|
|
type: 'fromAI',
|
|
extraProps: fromAIExtraProps,
|
|
extraPropValues: {},
|
|
};
|
|
expect(buildValueFromOverride(override, makeContext(''), true)).toEqual(
|
|
`={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('${DISPLAY_NAME}', \`\`, 'string') }}`,
|
|
);
|
|
expect(buildValueFromOverride(override, makeContext(''), false)).toEqual(
|
|
`={{ $fromAI('${DISPLAY_NAME}', \`\`, 'string') }}`,
|
|
);
|
|
|
|
const description = 'a description';
|
|
override.extraPropValues.description = description;
|
|
|
|
expect(buildValueFromOverride(override, makeContext(''), true)).toEqual(
|
|
`={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('${DISPLAY_NAME}', \`${description}\`, 'string') }}`,
|
|
);
|
|
expect(buildValueFromOverride(override, makeContext(''), false)).toEqual(
|
|
`={{ $fromAI('${DISPLAY_NAME}', \`${description}\`, 'string') }}`,
|
|
);
|
|
});
|
|
});
|