mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 18:12:04 +00:00
feat: Option to skip validation in getNodeParameter (#14726)
This commit is contained in:
@@ -18,6 +18,7 @@ import { ApplicationError, ExpressionError, NodeConnectionTypes } from 'n8n-work
|
||||
|
||||
import { describeCommonTests } from './shared-tests';
|
||||
import { ExecuteContext } from '../execute-context';
|
||||
import * as validateUtil from '../utils/validate-value-against-schema';
|
||||
|
||||
describe('ExecuteContext', () => {
|
||||
const testCredentialType = 'testCredential';
|
||||
@@ -177,6 +178,18 @@ describe('ExecuteContext', () => {
|
||||
const parameter = executeContext.getNodeParameter('testParameter', 0);
|
||||
expect(parameter).toEqual([{ name: undefined, value: undefined }]);
|
||||
});
|
||||
|
||||
it('should not validate parameter if skipValidation in options', () => {
|
||||
const validateSpy = jest.spyOn(validateUtil, 'validateValueAgainstSchema');
|
||||
|
||||
executeContext.getNodeParameter('testParameter', 0, '', {
|
||||
skipValidation: true,
|
||||
});
|
||||
|
||||
expect(validateSpy).not.toHaveBeenCalled();
|
||||
|
||||
validateSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCredentials', () => {
|
||||
|
||||
@@ -406,6 +406,8 @@ export abstract class NodeExecutionContext implements Omit<FunctionsBase, 'getCr
|
||||
});
|
||||
}
|
||||
|
||||
if (options?.skipValidation) return returnData;
|
||||
|
||||
// Validate parameter value if it has a schema defined(RMC) or validateType defined
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
returnData = validateValueAgainstSchema(
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
import type { MockProxy } from 'jest-mock-extended';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import type { IExecuteFunctions } from 'n8n-workflow';
|
||||
|
||||
import * as update from '../../../../v2/actions/record/update.operation';
|
||||
import * as transport from '../../../../v2/transport';
|
||||
import { createMockExecuteFunction } from '../helpers';
|
||||
@@ -38,6 +42,44 @@ jest.mock('../../../../v2/transport', () => {
|
||||
});
|
||||
|
||||
describe('Test AirtableV2, update operation', () => {
|
||||
let mockExecuteFunctions: MockProxy<IExecuteFunctions>;
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should skip validation if typecast option is true', async () => {
|
||||
mockExecuteFunctions = mock<IExecuteFunctions>();
|
||||
mockExecuteFunctions.helpers.constructExecutionMetaData = jest.fn(() => []);
|
||||
mockExecuteFunctions.getNodeParameter.mockImplementation((key: string) => {
|
||||
if (key === 'columns.mappingMode') {
|
||||
return 'defineBelow';
|
||||
}
|
||||
if (key === 'columns.matchingColumns') {
|
||||
return ['id'];
|
||||
}
|
||||
if (key === 'options') {
|
||||
return {
|
||||
typecast: true,
|
||||
};
|
||||
}
|
||||
if (key === 'columns.value') {
|
||||
return {
|
||||
id: 'recXXX',
|
||||
field1: 'foo 1',
|
||||
field2: 'bar 1',
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
await update.execute.call(mockExecuteFunctions, [{ json: {} }], 'base', 'table');
|
||||
|
||||
expect(mockExecuteFunctions.getNodeParameter).toHaveBeenCalledWith('columns.value', 0, [], {
|
||||
skipValidation: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('should update a record by id, autoMapInputData', async () => {
|
||||
const nodeParameters = {
|
||||
operation: 'update',
|
||||
|
||||
@@ -80,6 +80,7 @@ export async function execute(
|
||||
try {
|
||||
const records: UpdateRecord[] = [];
|
||||
const options = this.getNodeParameter('options', i, {});
|
||||
const typecast = options.typecast ? true : false;
|
||||
|
||||
if (dataMode === 'autoMapInputData') {
|
||||
if (columnsToMatchOn.includes('id')) {
|
||||
@@ -107,11 +108,22 @@ export async function execute(
|
||||
}
|
||||
|
||||
if (dataMode === 'defineBelow') {
|
||||
const getNodeParameterOptions = typecast ? { skipValidation: true } : undefined;
|
||||
if (columnsToMatchOn.includes('id')) {
|
||||
const { id, ...fields } = this.getNodeParameter('columns.value', i, []) as IDataObject;
|
||||
const { id, ...fields } = this.getNodeParameter(
|
||||
'columns.value',
|
||||
i,
|
||||
[],
|
||||
getNodeParameterOptions,
|
||||
) as IDataObject;
|
||||
records.push({ id: id as string, fields });
|
||||
} else {
|
||||
const fields = this.getNodeParameter('columns.value', i, []) as IDataObject;
|
||||
const fields = this.getNodeParameter(
|
||||
'columns.value',
|
||||
i,
|
||||
[],
|
||||
getNodeParameterOptions,
|
||||
) as IDataObject;
|
||||
|
||||
const matches = findMatches(
|
||||
tableData,
|
||||
@@ -127,7 +139,7 @@ export async function execute(
|
||||
}
|
||||
}
|
||||
|
||||
const body: IDataObject = { typecast: options.typecast ? true : false };
|
||||
const body: IDataObject = { typecast };
|
||||
|
||||
const responseData = await batchUpdate.call(this, endpoint, body, records);
|
||||
|
||||
|
||||
@@ -571,6 +571,8 @@ export interface IGetNodeParameterOptions {
|
||||
extractValue?: boolean;
|
||||
// get raw value of parameter with unresolved expressions
|
||||
rawExpressions?: boolean;
|
||||
// skip validation of parameter
|
||||
skipValidation?: boolean;
|
||||
}
|
||||
|
||||
namespace ExecuteFunctions {
|
||||
|
||||
Reference in New Issue
Block a user