feat: Better error when calling expression function on input that is undefined or null (#10009)

This commit is contained in:
Michael Kret
2024-07-11 15:36:39 +03:00
committed by GitHub
parent e3c138ffd2
commit 519e57bda5
7 changed files with 56 additions and 16 deletions

View File

@@ -17,6 +17,7 @@ import type { ExpressionChunk, ExpressionCode } from './ExpressionParser';
import { joinExpression, splitExpression } from './ExpressionParser';
import { booleanExtensions } from './BooleanExtensions';
import type { ExtensionMap } from './Extensions';
import { checkIfValueDefinedOrThrow } from './utils';
const EXPRESSION_EXTENDER = 'extend';
const EXPRESSION_EXTENDER_OPTIONAL = 'extendOptional';
@@ -514,6 +515,7 @@ export function extend(input: unknown, functionName: string, args: unknown[]) {
// any types have a function with that name. Then throw an error
// letting the user know the available types.
if (!foundFunction) {
checkIfValueDefinedOrThrow(input, functionName);
const haveFunction = EXTENSION_OBJECTS.filter((v) => functionName in v.functions);
if (!haveFunction.length) {
// This shouldn't really be possible but we should cover it anyway

View File

@@ -1,4 +1,5 @@
import { DateTime } from 'luxon';
import { ExpressionExtensionError } from '../errors/expression-extension.error';
// Utility functions and type guards for expression extensions
@@ -17,3 +18,15 @@ export const convertToDateTime = (value: string | Date | DateTime): DateTime | u
}
return converted;
};
export function checkIfValueDefinedOrThrow<T>(value: T, functionName: string): void {
if (value === undefined || value === null) {
throw new ExpressionExtensionError(
`${functionName}() could not be called on "${String(value)}" type`,
{
description:
'You are trying to access a field that does not exist, modify your expression or set a default value',
},
);
}
}

View File

@@ -4,9 +4,10 @@
/* eslint-disable n8n-local-rules/no-interpolation-in-regular-string */
import { extendTransform } from '@/Extensions';
import { extendTransform, extend } from '@/Extensions';
import { joinExpression, splitExpression } from '@/Extensions/ExpressionParser';
import { evaluate } from './Helpers';
import { ExpressionExtensionError } from '../../src/errors/expression-extension.error';
describe('Expression Extension Transforms', () => {
describe('extend() transform', () => {
@@ -242,4 +243,31 @@ describe('tmpl Expression Parser', () => {
expect(evaluate('={{ $ifEmpty({a: 1}, "default") }}')).toEqual({ a: 1 });
});
});
describe('Test extend with undefined', () => {
test('input is undefined', () => {
try {
extend(undefined, 'toDateTime', []);
} catch (error) {
expect(error).toBeInstanceOf(ExpressionExtensionError);
expect(error).toHaveProperty(
'message',
'toDateTime() could not be called on "undefined" type',
);
}
});
test('input is null', () => {
try {
extend(null, 'startsWith', []);
} catch (error) {
expect(error).toBeInstanceOf(ExpressionExtensionError);
expect(error).toHaveProperty('message', 'startsWith() could not be called on "null" type');
}
});
test('input should be converted to upper case', () => {
const result = extend('TEST', 'toUpperCase', []);
expect(result).toEqual('TEST');
});
});
});