mirror of
https://github.com/n8n-io/n8n.git
synced 2025-02-02 07:01:30 -08:00
146 lines
4 KiB
TypeScript
146 lines
4 KiB
TypeScript
|
import { get } from 'lodash';
|
||
|
import { constructExecutionMetaData } from 'n8n-core';
|
||
|
import {
|
||
|
NodeOperationError,
|
||
|
type IDataObject,
|
||
|
type IExecuteFunctions,
|
||
|
type IGetNodeParameterOptions,
|
||
|
type INode,
|
||
|
} from 'n8n-workflow';
|
||
|
|
||
|
import { type SetNodeOptions } from '../../v2/helpers/interfaces';
|
||
|
import * as utils from '../../v2/helpers/utils';
|
||
|
import { execute } from '../../v2/raw.mode';
|
||
|
|
||
|
const node: INode = {
|
||
|
id: '11',
|
||
|
name: 'Set Node',
|
||
|
type: 'n8n-nodes-base.set',
|
||
|
typeVersion: 3,
|
||
|
position: [42, 42],
|
||
|
parameters: {
|
||
|
mode: 'manual',
|
||
|
fields: {
|
||
|
values: [],
|
||
|
},
|
||
|
include: 'none',
|
||
|
options: {},
|
||
|
},
|
||
|
};
|
||
|
|
||
|
const createMockExecuteFunction = (
|
||
|
nodeParameters: IDataObject,
|
||
|
continueOnFail: boolean = false,
|
||
|
) => {
|
||
|
const fakeExecuteFunction = {
|
||
|
getNodeParameter(
|
||
|
parameterName: string,
|
||
|
_itemIndex: number,
|
||
|
fallbackValue?: IDataObject | undefined,
|
||
|
options?: IGetNodeParameterOptions | undefined,
|
||
|
) {
|
||
|
const parameter = options?.extractValue ? `${parameterName}.value` : parameterName;
|
||
|
return get(nodeParameters, parameter, fallbackValue);
|
||
|
},
|
||
|
getNode() {
|
||
|
return node;
|
||
|
},
|
||
|
helpers: { constructExecutionMetaData },
|
||
|
continueOnFail: () => continueOnFail,
|
||
|
} as unknown as IExecuteFunctions;
|
||
|
return fakeExecuteFunction;
|
||
|
};
|
||
|
|
||
|
describe('test Set2, rawMode/json Mode', () => {
|
||
|
const item = {
|
||
|
json: {
|
||
|
input1: 'value1',
|
||
|
input2: 2,
|
||
|
input3: [1, 2, 3],
|
||
|
},
|
||
|
pairedItem: {
|
||
|
item: 0,
|
||
|
input: undefined,
|
||
|
},
|
||
|
};
|
||
|
|
||
|
const options: SetNodeOptions = {
|
||
|
include: 'none',
|
||
|
};
|
||
|
|
||
|
afterEach(() => jest.resetAllMocks());
|
||
|
|
||
|
describe('fixed mode', () => {
|
||
|
const jsonData = { jsonData: 1 };
|
||
|
const fakeExecuteFunction = createMockExecuteFunction({ jsonOutput: jsonData });
|
||
|
const rawData = {
|
||
|
num1: 55,
|
||
|
str1: '42',
|
||
|
arr1: ['foo', 'bar'],
|
||
|
obj: {
|
||
|
key: 'value',
|
||
|
},
|
||
|
};
|
||
|
|
||
|
it('should parse json with the jsonOutput in node parameter and compose a return item', async () => {
|
||
|
jest.spyOn(utils, 'parseJsonParameter');
|
||
|
jest.spyOn(utils, 'composeReturnItem');
|
||
|
|
||
|
const result = await execute.call(fakeExecuteFunction, item, 0, options, rawData, node);
|
||
|
|
||
|
expect(result).toEqual({ json: jsonData, pairedItem: { item: 0 } });
|
||
|
expect(utils.parseJsonParameter).toHaveBeenCalledWith(jsonData, node, 0);
|
||
|
expect(utils.composeReturnItem).toHaveBeenCalledWith(0, item, jsonData, options, 3);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('expression mode', () => {
|
||
|
const jsonData = { my_field_1: 'value' };
|
||
|
const jsonDataString = '{"my_field_1": "value"}';
|
||
|
const fakeExecuteFunction = createMockExecuteFunction({ jsonOutput: jsonDataString });
|
||
|
const rawData = {
|
||
|
num1: 55,
|
||
|
str1: '42',
|
||
|
arr1: ['foo', 'bar'],
|
||
|
obj: {
|
||
|
key: 'value',
|
||
|
},
|
||
|
jsonOutput: jsonDataString,
|
||
|
};
|
||
|
|
||
|
it('should parse json with resolved expression data and compose a return item', async () => {
|
||
|
jest.spyOn(utils, 'parseJsonParameter');
|
||
|
jest.spyOn(utils, 'composeReturnItem');
|
||
|
jest.spyOn(utils, 'resolveRawData');
|
||
|
|
||
|
const result = await execute.call(fakeExecuteFunction, item, 0, options, rawData, node);
|
||
|
|
||
|
expect(utils.parseJsonParameter).toHaveBeenCalledWith(jsonDataString, node, 0);
|
||
|
expect(utils.composeReturnItem).toHaveBeenCalledWith(0, item, jsonData, options, 3);
|
||
|
expect(utils.resolveRawData).toHaveBeenCalledWith(jsonDataString, 0);
|
||
|
expect(result).toEqual({ json: jsonData, pairedItem: { item: 0 } });
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('error handling', () => {
|
||
|
it('should return an error object with pairedItem when continueOnFail is true', async () => {
|
||
|
const fakeExecuteFunction = createMockExecuteFunction({ jsonOutput: 'jsonData' }, true);
|
||
|
|
||
|
const output = await execute.call(fakeExecuteFunction, item, 0, options, {}, node);
|
||
|
|
||
|
expect(output).toEqual({
|
||
|
json: { error: "The 'JSON Output' in item 0 contains invalid JSON" },
|
||
|
pairedItem: { item: 0 },
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it('should throw an error when continueOnFail is false', async () => {
|
||
|
const fakeExecuteFunction = createMockExecuteFunction({ jsonOutput: 'jsonData' }, false);
|
||
|
|
||
|
await expect(execute.call(fakeExecuteFunction, item, 0, options, {}, node)).rejects.toThrow(
|
||
|
NodeOperationError,
|
||
|
);
|
||
|
});
|
||
|
});
|
||
|
});
|