mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-16 09:36:44 +00:00
fix(Set Node): Handle special replacement patterns in JSON expressions (#18162)
This commit is contained in:
@@ -3,7 +3,12 @@ import { constructExecutionMetaData } from 'n8n-core';
|
||||
import type { IDataObject, IExecuteFunctions, IGetNodeParameterOptions, INode } from 'n8n-workflow';
|
||||
|
||||
import type { SetNodeOptions } from '../../v2/helpers/interfaces';
|
||||
import { composeReturnItem, parseJsonParameter, validateEntry } from '../../v2/helpers/utils';
|
||||
import {
|
||||
composeReturnItem,
|
||||
parseJsonParameter,
|
||||
validateEntry,
|
||||
resolveRawData,
|
||||
} from '../../v2/helpers/utils';
|
||||
|
||||
export const node: INode = {
|
||||
id: '11',
|
||||
@@ -342,3 +347,89 @@ describe('test Set2, validateEntry', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('test Set2, resolveRawData', () => {
|
||||
const createMockExecuteFunctionForResolve = (returnValue: any) => {
|
||||
return {
|
||||
evaluateExpression: jest.fn().mockReturnValue(returnValue),
|
||||
} as unknown as IExecuteFunctions;
|
||||
};
|
||||
|
||||
it('should handle strings with special replacement patterns like $&', () => {
|
||||
const mockFunction = createMockExecuteFunctionForResolve('hello world $&');
|
||||
const input = '{{ "hello world $&" }}';
|
||||
const result = resolveRawData.call(mockFunction, input, 0);
|
||||
|
||||
// The result should contain the literal $& and not have it replaced
|
||||
expect(result).toBe('hello world $&');
|
||||
expect(mockFunction.evaluateExpression).toHaveBeenCalledWith('{{ "hello world $&" }}', 0);
|
||||
});
|
||||
|
||||
it('should handle strings with $` pattern', () => {
|
||||
const mockFunction = createMockExecuteFunctionForResolve('hello world $`');
|
||||
const input = '{{ "hello world $`" }}';
|
||||
const result = resolveRawData.call(mockFunction, input, 0);
|
||||
|
||||
expect(result).toBe('hello world $`');
|
||||
});
|
||||
|
||||
it("should handle strings with $' pattern", () => {
|
||||
const mockFunction = createMockExecuteFunctionForResolve("hello world $'");
|
||||
const input = '{{ "hello world $\'" }}';
|
||||
const result = resolveRawData.call(mockFunction, input, 0);
|
||||
|
||||
expect(result).toBe("hello world $'");
|
||||
});
|
||||
|
||||
it('should handle strings with $n pattern', () => {
|
||||
const mockFunction = createMockExecuteFunctionForResolve('hello world $1 $2');
|
||||
const input = '{{ "hello world $1 $2" }}';
|
||||
const result = resolveRawData.call(mockFunction, input, 0);
|
||||
|
||||
expect(result).toBe('hello world $1 $2');
|
||||
});
|
||||
|
||||
it('should handle JSON objects with special patterns', () => {
|
||||
const mockFunction = createMockExecuteFunctionForResolve({ message: 'hello world $&' });
|
||||
const input = '{{ {"message": "hello world $&"} }}';
|
||||
const result = resolveRawData.call(mockFunction, input, 0);
|
||||
|
||||
expect(result).toBe('{"message":"hello world $&"}');
|
||||
});
|
||||
|
||||
it('should handle multiple expressions with special patterns', () => {
|
||||
const mockFunction = {
|
||||
evaluateExpression: jest.fn().mockReturnValueOnce('hello $&').mockReturnValueOnce('world $`'),
|
||||
} as unknown as IExecuteFunctions;
|
||||
|
||||
const input = 'start {{ expr1 }} middle {{ expr2 }} end';
|
||||
const result = resolveRawData.call(mockFunction, input, 0);
|
||||
|
||||
expect(result).toBe('start hello $& middle world $` end');
|
||||
});
|
||||
|
||||
it('should handle regular strings without special patterns', () => {
|
||||
const mockFunction = createMockExecuteFunctionForResolve('hello world');
|
||||
const input = '{{ "hello world" }}';
|
||||
const result = resolveRawData.call(mockFunction, input, 0);
|
||||
|
||||
expect(result).toBe('hello world');
|
||||
});
|
||||
|
||||
it('should handle objects and stringify them', () => {
|
||||
const mockFunction = createMockExecuteFunctionForResolve({ message: 'hello world', count: 42 });
|
||||
const input = '{{ someExpression }}';
|
||||
const result = resolveRawData.call(mockFunction, input, 0);
|
||||
|
||||
expect(result).toBe('{"message":"hello world","count":42}');
|
||||
});
|
||||
|
||||
it('should return raw data when no resolvables are found', () => {
|
||||
const mockFunction = createMockExecuteFunctionForResolve('unused');
|
||||
const input = 'hello world without expressions';
|
||||
const result = resolveRawData.call(mockFunction, input, 0);
|
||||
|
||||
expect(result).toBe('hello world without expressions');
|
||||
expect(mockFunction.evaluateExpression).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -232,10 +232,11 @@ export function resolveRawData(
|
||||
for (const resolvable of resolvables) {
|
||||
const resolvedValue = this.evaluateExpression(`${resolvable}`, i);
|
||||
|
||||
// Use a function replacer to avoid issues with special replacement patterns like $&
|
||||
if (typeof resolvedValue === 'object' && resolvedValue !== null) {
|
||||
returnData = returnData.replace(resolvable, JSON.stringify(resolvedValue));
|
||||
returnData = returnData.replace(resolvable, () => JSON.stringify(resolvedValue));
|
||||
} else {
|
||||
returnData = returnData.replace(resolvable, resolvedValue as string);
|
||||
returnData = returnData.replace(resolvable, () => String(resolvedValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user