first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,570 @@
|
||||
import { mockDeep } from 'jest-mock-extended';
|
||||
import type {
|
||||
IExecuteFunctions,
|
||||
ILoadOptionsFunctions,
|
||||
INodeTypeBaseDescription,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeOperationError, ApplicationError } from 'n8n-workflow';
|
||||
|
||||
import { SwitchV3 } from '../SwitchV3.node';
|
||||
|
||||
describe('SwitchV3 Node', () => {
|
||||
let switchNode: SwitchV3;
|
||||
let mockExecuteFunctions: jest.Mocked<IExecuteFunctions>;
|
||||
let mockLoadOptionsFunctions: jest.Mocked<ILoadOptionsFunctions>;
|
||||
|
||||
const baseDescription: INodeTypeBaseDescription = {
|
||||
displayName: 'Switch',
|
||||
name: 'n8n-nodes-base.switch',
|
||||
group: ['transform'],
|
||||
description: 'Route items to different outputs',
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
switchNode = new SwitchV3(baseDescription);
|
||||
mockExecuteFunctions = mockDeep<IExecuteFunctions>();
|
||||
mockLoadOptionsFunctions = mockDeep<ILoadOptionsFunctions>();
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('Version-specific behavior', () => {
|
||||
it('should have two numberOutputs parameters with different version conditions', () => {
|
||||
const switchNode = new SwitchV3(baseDescription);
|
||||
const numberOutputsParams = switchNode.description.properties.filter(
|
||||
(prop) => prop.name === 'numberOutputs',
|
||||
);
|
||||
|
||||
expect(numberOutputsParams).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('should have noDataExpression: true for version 3.3+ numberOutputs parameter', () => {
|
||||
const switchNode = new SwitchV3(baseDescription);
|
||||
const numberOutputsParamWithNoExpression = switchNode.description.properties.find(
|
||||
(prop) => prop.name === 'numberOutputs' && prop.noDataExpression === true,
|
||||
);
|
||||
|
||||
expect(numberOutputsParamWithNoExpression).toBeDefined();
|
||||
expect(numberOutputsParamWithNoExpression?.noDataExpression).toBe(true);
|
||||
expect(numberOutputsParamWithNoExpression?.displayOptions?.show?.['@version']).toEqual([
|
||||
{ _cnd: { gte: 3.3 } },
|
||||
]);
|
||||
});
|
||||
|
||||
it('should have numberOutputs parameter without noDataExpression for older versions', () => {
|
||||
const switchNode = new SwitchV3(baseDescription);
|
||||
const numberOutputsParamWithoutNoExpression = switchNode.description.properties.find(
|
||||
(prop) => prop.name === 'numberOutputs' && !prop.noDataExpression,
|
||||
);
|
||||
|
||||
expect(numberOutputsParamWithoutNoExpression).toBeDefined();
|
||||
expect(numberOutputsParamWithoutNoExpression?.noDataExpression).toBeUndefined();
|
||||
expect(numberOutputsParamWithoutNoExpression?.displayOptions?.show?.['@version']).toEqual([
|
||||
{ _cnd: { lt: 3.3 } },
|
||||
]);
|
||||
});
|
||||
|
||||
it('should include version 3.3 in supported versions', () => {
|
||||
const switchNode = new SwitchV3(baseDescription);
|
||||
expect(switchNode.description.version).toContain(3.3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Expression Mode Execution', () => {
|
||||
beforeEach(() => {
|
||||
mockExecuteFunctions.getNode.mockReturnValue({
|
||||
id: 'switch-node',
|
||||
name: 'Switch',
|
||||
type: 'n8n-nodes-base.switch',
|
||||
typeVersion: 3.3,
|
||||
position: [0, 0],
|
||||
parameters: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should route items to correct output in expression mode', async () => {
|
||||
const inputData = [{ json: { value: 1 } }, { json: { value: 2 } }, { json: { value: 3 } }];
|
||||
|
||||
mockExecuteFunctions.getInputData.mockReturnValue(inputData);
|
||||
mockExecuteFunctions.getNodeParameter.mockImplementation(
|
||||
(paramName: string, itemIndex: number) => {
|
||||
const params: Record<string, any> = {
|
||||
mode: 'expression',
|
||||
numberOutputs: 3,
|
||||
output: itemIndex % 3,
|
||||
};
|
||||
return params[paramName];
|
||||
},
|
||||
);
|
||||
|
||||
const result = await switchNode.execute.call(mockExecuteFunctions);
|
||||
|
||||
expect(result).toHaveLength(3);
|
||||
expect(result[0]).toHaveLength(1);
|
||||
expect(result[0][0].json).toEqual({ value: 1 });
|
||||
expect(result[1]).toHaveLength(1);
|
||||
expect(result[1][0].json).toEqual({ value: 2 });
|
||||
expect(result[2]).toHaveLength(1);
|
||||
expect(result[2][0].json).toEqual({ value: 3 });
|
||||
});
|
||||
|
||||
it('should handle multiple items routed to same output', async () => {
|
||||
const inputData = [{ json: { value: 1 } }, { json: { value: 2 } }, { json: { value: 3 } }];
|
||||
|
||||
mockExecuteFunctions.getInputData.mockReturnValue(inputData);
|
||||
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
||||
const params: Record<string, any> = {
|
||||
mode: 'expression',
|
||||
numberOutputs: 2,
|
||||
output: 0,
|
||||
};
|
||||
return params[paramName];
|
||||
});
|
||||
|
||||
const result = await switchNode.execute.call(mockExecuteFunctions);
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result[0]).toHaveLength(3);
|
||||
expect(result[1]).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should throw error for invalid output index', async () => {
|
||||
const inputData = [{ json: { value: 1 } }];
|
||||
|
||||
mockExecuteFunctions.getInputData.mockReturnValue(inputData);
|
||||
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
||||
const params: Record<string, any> = {
|
||||
mode: 'expression',
|
||||
numberOutputs: 2,
|
||||
output: 5,
|
||||
};
|
||||
return params[paramName];
|
||||
});
|
||||
|
||||
await expect(switchNode.execute.call(mockExecuteFunctions)).rejects.toThrow(
|
||||
NodeOperationError,
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw error for negative output index', async () => {
|
||||
const inputData = [{ json: { value: 1 } }];
|
||||
|
||||
mockExecuteFunctions.getInputData.mockReturnValue(inputData);
|
||||
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
||||
const params: Record<string, any> = {
|
||||
mode: 'expression',
|
||||
numberOutputs: 2,
|
||||
output: -1,
|
||||
};
|
||||
return params[paramName];
|
||||
});
|
||||
|
||||
await expect(switchNode.execute.call(mockExecuteFunctions)).rejects.toThrow(
|
||||
NodeOperationError,
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle empty input data', async () => {
|
||||
mockExecuteFunctions.getInputData.mockReturnValue([]);
|
||||
mockExecuteFunctions.getNodeParameter.mockReturnValue('expression');
|
||||
|
||||
const result = await switchNode.execute.call(mockExecuteFunctions);
|
||||
|
||||
expect(result).toEqual([[]]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Rules Mode Execution', () => {
|
||||
beforeEach(() => {
|
||||
mockExecuteFunctions.getNode.mockReturnValue({
|
||||
id: 'switch-node',
|
||||
name: 'Switch',
|
||||
type: 'n8n-nodes-base.switch',
|
||||
typeVersion: 3.3,
|
||||
position: [0, 0],
|
||||
parameters: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should route items based on matching rules', async () => {
|
||||
const inputData = [
|
||||
{ json: { status: 'active' } },
|
||||
{ json: { status: 'inactive' } },
|
||||
{ json: { status: 'pending' } },
|
||||
];
|
||||
|
||||
mockExecuteFunctions.getInputData.mockReturnValue(inputData);
|
||||
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
||||
if (paramName === 'mode') return 'rules';
|
||||
if (paramName === 'rules.values') {
|
||||
return [
|
||||
{
|
||||
conditions: {
|
||||
conditions: [
|
||||
{
|
||||
leftValue: '={{$json.status}}',
|
||||
rightValue: 'active',
|
||||
operator: { type: 'string', operation: 'equals' },
|
||||
},
|
||||
],
|
||||
combinator: 'and',
|
||||
},
|
||||
},
|
||||
{
|
||||
conditions: {
|
||||
conditions: [
|
||||
{
|
||||
leftValue: '={{$json.status}}',
|
||||
rightValue: 'inactive',
|
||||
operator: { type: 'string', operation: 'equals' },
|
||||
},
|
||||
],
|
||||
combinator: 'and',
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
if (paramName === 'options') return {};
|
||||
return false;
|
||||
});
|
||||
|
||||
mockExecuteFunctions.getNodeParameter.mockImplementation(
|
||||
(paramName: string, itemIndex: number, defaultValue: any, options?: any) => {
|
||||
if (paramName === 'mode') return 'rules';
|
||||
if (paramName === 'rules.values') {
|
||||
return [
|
||||
{ conditions: { conditions: [], combinator: 'and' } },
|
||||
{ conditions: { conditions: [], combinator: 'and' } },
|
||||
];
|
||||
}
|
||||
if (paramName === 'options') return {};
|
||||
if (paramName.includes('conditions') && options?.extractValue) {
|
||||
if (itemIndex === 0) return true; // active matches first rule
|
||||
if (itemIndex === 1) return false; // inactive doesn't match first rule
|
||||
return false;
|
||||
}
|
||||
return defaultValue;
|
||||
},
|
||||
);
|
||||
|
||||
const result = await switchNode.execute.call(mockExecuteFunctions);
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result[0]).toHaveLength(1);
|
||||
expect(result[0][0].json).toEqual({ status: 'active' });
|
||||
expect(result[1]).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should handle fallback output when no rules match', async () => {
|
||||
const inputData = [{ json: { status: 'unknown' } }];
|
||||
|
||||
mockExecuteFunctions.getInputData.mockReturnValue(inputData);
|
||||
mockExecuteFunctions.getNodeParameter.mockImplementation(
|
||||
(paramName: string, _itemIndex: number, defaultValue: any, options?: any) => {
|
||||
if (paramName === 'mode') return 'rules';
|
||||
if (paramName === 'rules.values') {
|
||||
return [{ conditions: { conditions: [], combinator: 'and' } }];
|
||||
}
|
||||
if (paramName === 'options') return { fallbackOutput: 'extra' };
|
||||
if (paramName.includes('conditions') && options?.extractValue) {
|
||||
return false; // No rule matches
|
||||
}
|
||||
return defaultValue;
|
||||
},
|
||||
);
|
||||
|
||||
const result = await switchNode.execute.call(mockExecuteFunctions);
|
||||
|
||||
expect(result).toHaveLength(2); // One rule output + one fallback output
|
||||
expect(result[0]).toHaveLength(0); // No matches for rule
|
||||
expect(result[1]).toHaveLength(1); // Item goes to fallback
|
||||
expect(result[1][0].json).toEqual({ status: 'unknown' });
|
||||
});
|
||||
|
||||
it('should handle allMatchingOutputs option', async () => {
|
||||
const inputData = [{ json: { value: 10 } }];
|
||||
|
||||
mockExecuteFunctions.getInputData.mockReturnValue(inputData);
|
||||
mockExecuteFunctions.getNodeParameter.mockImplementation(
|
||||
(paramName: string, _itemIndex: number, defaultValue: any, options?: any) => {
|
||||
if (paramName === 'mode') return 'rules';
|
||||
if (paramName === 'rules.values') {
|
||||
return [
|
||||
{ conditions: { conditions: [], combinator: 'and' } },
|
||||
{ conditions: { conditions: [], combinator: 'and' } },
|
||||
];
|
||||
}
|
||||
if (paramName === 'options') return { allMatchingOutputs: true };
|
||||
if (paramName.includes('conditions') && options?.extractValue) {
|
||||
return true; // Both rules match
|
||||
}
|
||||
return defaultValue;
|
||||
},
|
||||
);
|
||||
|
||||
const result = await switchNode.execute.call(mockExecuteFunctions);
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result[0]).toHaveLength(1);
|
||||
expect(result[1]).toHaveLength(1);
|
||||
expect(result[0][0].json).toEqual({ value: 10 });
|
||||
expect(result[1][0].json).toEqual({ value: 10 });
|
||||
});
|
||||
|
||||
it('should skip items when no rules are defined', async () => {
|
||||
const inputData = [{ json: { value: 1 } }];
|
||||
|
||||
mockExecuteFunctions.getInputData.mockReturnValue(inputData);
|
||||
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
||||
if (paramName === 'mode') return 'rules';
|
||||
if (paramName === 'rules.values') return [];
|
||||
if (paramName === 'options') return {};
|
||||
return undefined;
|
||||
});
|
||||
|
||||
const result = await switchNode.execute.call(mockExecuteFunctions);
|
||||
|
||||
expect(result).toEqual([[]]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Error Handling', () => {
|
||||
beforeEach(() => {
|
||||
mockExecuteFunctions.getNode.mockReturnValue({
|
||||
id: 'switch-node',
|
||||
name: 'Switch',
|
||||
type: 'n8n-nodes-base.switch',
|
||||
typeVersion: 3.3,
|
||||
position: [0, 0],
|
||||
parameters: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle errors with continueOnFail', async () => {
|
||||
const inputData = [{ json: { value: 1 } }];
|
||||
|
||||
mockExecuteFunctions.getInputData.mockReturnValue(inputData);
|
||||
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
||||
if (paramName === 'mode') return 'expression';
|
||||
if (paramName === 'numberOutputs') return 1;
|
||||
if (paramName === 'output') {
|
||||
throw new Error('Parameter error');
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
mockExecuteFunctions.continueOnFail.mockReturnValue(true);
|
||||
|
||||
const result = await switchNode.execute.call(mockExecuteFunctions);
|
||||
|
||||
expect(result[0][0].json).toHaveProperty('error', 'Parameter error');
|
||||
});
|
||||
|
||||
it('should rethrow NodeOperationError', async () => {
|
||||
const inputData = [{ json: { value: 1 } }];
|
||||
|
||||
mockExecuteFunctions.getInputData.mockReturnValue(inputData);
|
||||
mockExecuteFunctions.getNodeParameter.mockImplementation(() => {
|
||||
throw new NodeOperationError(mockExecuteFunctions.getNode(), 'Invalid parameter');
|
||||
});
|
||||
|
||||
await expect(switchNode.execute.call(mockExecuteFunctions)).rejects.toThrow(
|
||||
NodeOperationError,
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle ApplicationError with context', async () => {
|
||||
const inputData = [{ json: { value: 1 } }];
|
||||
|
||||
mockExecuteFunctions.getInputData.mockReturnValue(inputData);
|
||||
mockExecuteFunctions.getNodeParameter.mockImplementation(() => {
|
||||
const error = new ApplicationError('Application error');
|
||||
throw error;
|
||||
});
|
||||
|
||||
await expect(switchNode.execute.call(mockExecuteFunctions)).rejects.toThrow(ApplicationError);
|
||||
});
|
||||
|
||||
it('should wrap generic errors in NodeOperationError', async () => {
|
||||
const inputData = [{ json: { value: 1 } }];
|
||||
|
||||
mockExecuteFunctions.getInputData.mockReturnValue(inputData);
|
||||
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
||||
if (paramName === 'mode') return 'expression';
|
||||
if (paramName === 'numberOutputs') return 1;
|
||||
if (paramName === 'output') {
|
||||
throw new Error('Generic error');
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
await expect(switchNode.execute.call(mockExecuteFunctions)).rejects.toThrow(
|
||||
NodeOperationError,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Load Options', () => {
|
||||
it('should load fallback output options with no rules', async () => {
|
||||
mockLoadOptionsFunctions.getCurrentNodeParameter.mockReturnValue([]);
|
||||
|
||||
const result =
|
||||
await switchNode.methods.loadOptions.getFallbackOutputOptions.call(
|
||||
mockLoadOptionsFunctions,
|
||||
);
|
||||
|
||||
expect(result).toEqual([
|
||||
{
|
||||
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
|
||||
name: 'None (default)',
|
||||
value: 'none',
|
||||
description: 'Items will be ignored',
|
||||
},
|
||||
{
|
||||
name: 'Extra Output',
|
||||
value: 'extra',
|
||||
description: 'Items will be sent to the extra, separate, output',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should load fallback output options with rules', async () => {
|
||||
const rules = [
|
||||
{ outputKey: 'Rule 1' },
|
||||
{ outputKey: 'Rule 2' },
|
||||
{}, // Rule without outputKey
|
||||
];
|
||||
|
||||
mockLoadOptionsFunctions.getCurrentNodeParameter.mockReturnValue(rules);
|
||||
|
||||
const result =
|
||||
await switchNode.methods.loadOptions.getFallbackOutputOptions.call(
|
||||
mockLoadOptionsFunctions,
|
||||
);
|
||||
|
||||
expect(result).toEqual([
|
||||
{
|
||||
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
|
||||
name: 'None (default)',
|
||||
value: 'none',
|
||||
description: 'Items will be ignored',
|
||||
},
|
||||
{
|
||||
name: 'Extra Output',
|
||||
value: 'extra',
|
||||
description: 'Items will be sent to the extra, separate, output',
|
||||
},
|
||||
{
|
||||
name: 'Output Rule 1',
|
||||
value: 0,
|
||||
description: 'Items will be sent to the same output as when matched rule 1',
|
||||
},
|
||||
{
|
||||
name: 'Output Rule 2',
|
||||
value: 1,
|
||||
description: 'Items will be sent to the same output as when matched rule 2',
|
||||
},
|
||||
{
|
||||
name: 'Output 2',
|
||||
value: 2,
|
||||
description: 'Items will be sent to the same output as when matched rule 3',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should handle null rules parameter', async () => {
|
||||
mockLoadOptionsFunctions.getCurrentNodeParameter.mockReturnValue(null);
|
||||
|
||||
const result =
|
||||
await switchNode.methods.loadOptions.getFallbackOutputOptions.call(
|
||||
mockLoadOptionsFunctions,
|
||||
);
|
||||
|
||||
expect(result).toEqual([
|
||||
{
|
||||
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
|
||||
name: 'None (default)',
|
||||
value: 'none',
|
||||
description: 'Items will be ignored',
|
||||
},
|
||||
{
|
||||
name: 'Extra Output',
|
||||
value: 'extra',
|
||||
description: 'Items will be sent to the extra, separate, output',
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Edge Cases', () => {
|
||||
beforeEach(() => {
|
||||
mockExecuteFunctions.getNode.mockReturnValue({
|
||||
id: 'switch-node',
|
||||
name: 'Switch',
|
||||
type: 'n8n-nodes-base.switch',
|
||||
typeVersion: 3.3,
|
||||
position: [0, 0],
|
||||
parameters: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle items with pairedItem already set', async () => {
|
||||
const inputData = [{ json: { value: 1 }, pairedItem: { item: 5 } }];
|
||||
|
||||
mockExecuteFunctions.getInputData.mockReturnValue(inputData);
|
||||
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
||||
const params: Record<string, any> = {
|
||||
mode: 'expression',
|
||||
numberOutputs: 1,
|
||||
output: 0,
|
||||
};
|
||||
return params[paramName];
|
||||
});
|
||||
|
||||
const result = await switchNode.execute.call(mockExecuteFunctions);
|
||||
|
||||
expect(result[0][0].pairedItem).toEqual({ item: 0 });
|
||||
});
|
||||
|
||||
it('should handle output index equal to returnData length', async () => {
|
||||
const inputData = [{ json: { value: 1 } }];
|
||||
|
||||
mockExecuteFunctions.getInputData.mockReturnValue(inputData);
|
||||
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
||||
const params: Record<string, any> = {
|
||||
mode: 'expression',
|
||||
numberOutputs: 2,
|
||||
output: 2, // Equal to returnData length
|
||||
};
|
||||
return params[paramName];
|
||||
});
|
||||
|
||||
await expect(switchNode.execute.call(mockExecuteFunctions)).rejects.toThrow(
|
||||
NodeOperationError,
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle fallback output to existing rule output', async () => {
|
||||
const inputData = [{ json: { status: 'unknown' } }];
|
||||
|
||||
mockExecuteFunctions.getInputData.mockReturnValue(inputData);
|
||||
mockExecuteFunctions.getNodeParameter.mockImplementation(
|
||||
(paramName: string, _itemIndex: number, defaultValue: any, options?: any) => {
|
||||
if (paramName === 'mode') return 'rules';
|
||||
if (paramName === 'rules.values') {
|
||||
return [{ conditions: { conditions: [], combinator: 'and' } }];
|
||||
}
|
||||
if (paramName === 'options') return { fallbackOutput: 0 };
|
||||
if (paramName.includes('conditions') && options?.extractValue) {
|
||||
return false; // No rule matches
|
||||
}
|
||||
return defaultValue;
|
||||
},
|
||||
);
|
||||
|
||||
const result = await switchNode.execute.call(mockExecuteFunctions);
|
||||
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0]).toHaveLength(1);
|
||||
expect(result[0][0].json).toEqual({ status: 'unknown' });
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user