fix(Airtable Node): Create record: skip type validation when typecast is enabled (#18393)

This commit is contained in:
Elias Meire
2025-08-15 18:59:31 +02:00
committed by GitHub
parent 726f0ff37a
commit dcd060ce33
3 changed files with 74 additions and 20 deletions

View File

@@ -15,23 +15,25 @@ export const node: INode = {
export const createMockExecuteFunction = (nodeParameters: IDataObject) => {
const fakeExecuteFunction = {
getInputData() {
getInputData: jest.fn(() => {
return [{ json: {} }];
},
getNodeParameter(
parameterName: string,
_itemIndex: number,
fallbackValue?: IDataObject,
options?: IGetNodeParameterOptions,
) {
const parameter = options?.extractValue ? `${parameterName}.value` : parameterName;
return get(nodeParameters, parameter, fallbackValue);
},
getNode() {
}),
getNodeParameter: jest.fn(
(
parameterName: string,
_itemIndex: number,
fallbackValue?: IDataObject,
options?: IGetNodeParameterOptions,
) => {
const parameter = options?.extractValue ? `${parameterName}.value` : parameterName;
return get(nodeParameters, parameter, fallbackValue);
},
),
getNode: jest.fn(() => {
return node;
},
helpers: { constructExecutionMetaData },
continueOnFail: () => false,
}),
helpers: { constructExecutionMetaData: jest.fn(constructExecutionMetaData) },
continueOnFail: jest.fn(() => false),
} as unknown as IExecuteFunctions;
return fakeExecuteFunction;
};

View File

@@ -154,4 +154,55 @@ describe('Test AirtableV2, create operation', () => {
typecast: false,
});
});
it('should skip validation if typecast option is true', async () => {
const nodeParameters = {
operation: 'create',
columns: {
mappingMode: 'defineBelow',
value: {
bar: 'bar 1',
foo: 'foo 1',
},
matchingColumns: [],
schema: [
{
id: 'foo',
displayName: 'foo',
required: false,
defaultMatch: false,
display: true,
type: 'string',
},
{
id: 'bar',
displayName: 'bar',
required: false,
defaultMatch: false,
display: true,
type: 'string',
},
],
},
options: {
typecast: true,
},
};
const mockExecuteFunctions = createMockExecuteFunction(nodeParameters);
await create.execute.call(mockExecuteFunctions, [{ json: {} }], 'appYoLbase', 'tblltable');
expect(mockExecuteFunctions.getNodeParameter).toHaveBeenCalledWith('columns.value', 0, [], {
skipValidation: true,
});
expect(transport.apiRequest).toHaveBeenCalledTimes(1);
expect(transport.apiRequest).toHaveBeenCalledWith('POST', 'appYoLbase/tblltable', {
fields: {
foo: 'foo 1',
bar: 'bar 1',
},
typecast: true,
});
});
});

View File

@@ -63,17 +63,18 @@ export async function execute(
for (let i = 0; i < items.length; i++) {
try {
const options = this.getNodeParameter('options', i, {});
const typecast = Boolean(options.typecast);
const body: IDataObject = {
typecast: options.typecast ? true : false,
};
const body: IDataObject = { typecast };
if (dataMode === 'autoMapInputData') {
body.fields = removeIgnored(items[i].json, options.ignoreFields as string);
}
if (dataMode === 'defineBelow') {
const fields = this.getNodeParameter('columns.value', i, []) as IDataObject;
const fields = this.getNodeParameter('columns.value', i, [], {
skipValidation: typecast,
}) as IDataObject;
body.fields = fields;
}
@@ -85,7 +86,7 @@ export async function execute(
{ itemData: { item: i } },
);
returnData.push(...executionData);
returnData.push.apply(returnData, executionData);
} catch (error) {
error = processAirtableError(error as NodeApiError, undefined, i);
if (this.continueOnFail()) {