mirror of
https://github.com/The-Low-Code-Foundation/OpenNoodl.git
synced 2026-01-12 07:12:54 +01:00
new code editor
This commit is contained in:
279
packages/noodl-editor/tests/models/expression-parameter.test.ts
Normal file
279
packages/noodl-editor/tests/models/expression-parameter.test.ts
Normal file
@@ -0,0 +1,279 @@
|
||||
/**
|
||||
* Expression Parameter Types Tests
|
||||
*
|
||||
* Tests type definitions and helper functions for expression-based parameters
|
||||
*/
|
||||
|
||||
import {
|
||||
ExpressionParameter,
|
||||
isExpressionParameter,
|
||||
getParameterDisplayValue,
|
||||
getParameterActualValue,
|
||||
createExpressionParameter,
|
||||
toParameter
|
||||
} from '../../src/editor/src/models/ExpressionParameter';
|
||||
|
||||
describe('Expression Parameter Types', () => {
|
||||
describe('isExpressionParameter', () => {
|
||||
it('identifies expression parameters', () => {
|
||||
const expr: ExpressionParameter = {
|
||||
mode: 'expression',
|
||||
expression: 'Variables.x + 1',
|
||||
fallback: 0
|
||||
};
|
||||
expect(isExpressionParameter(expr)).toBe(true);
|
||||
});
|
||||
|
||||
it('identifies expression without fallback', () => {
|
||||
const expr: ExpressionParameter = {
|
||||
mode: 'expression',
|
||||
expression: 'Variables.x'
|
||||
};
|
||||
expect(isExpressionParameter(expr)).toBe(true);
|
||||
});
|
||||
|
||||
it('rejects simple values', () => {
|
||||
expect(isExpressionParameter(42)).toBe(false);
|
||||
expect(isExpressionParameter('hello')).toBe(false);
|
||||
expect(isExpressionParameter(true)).toBe(false);
|
||||
expect(isExpressionParameter(null)).toBe(false);
|
||||
expect(isExpressionParameter(undefined)).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects objects without mode', () => {
|
||||
expect(isExpressionParameter({ expression: 'test' })).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects objects with wrong mode', () => {
|
||||
expect(isExpressionParameter({ mode: 'fixed', value: 42 })).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects objects without expression', () => {
|
||||
expect(isExpressionParameter({ mode: 'expression' })).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects objects with non-string expression', () => {
|
||||
expect(isExpressionParameter({ mode: 'expression', expression: 42 })).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getParameterDisplayValue', () => {
|
||||
it('returns expression string for expression parameters', () => {
|
||||
const expr: ExpressionParameter = {
|
||||
mode: 'expression',
|
||||
expression: 'Variables.x * 2',
|
||||
fallback: 0
|
||||
};
|
||||
expect(getParameterDisplayValue(expr)).toBe('Variables.x * 2');
|
||||
});
|
||||
|
||||
it('returns expression even without fallback', () => {
|
||||
const expr: ExpressionParameter = {
|
||||
mode: 'expression',
|
||||
expression: 'Variables.count'
|
||||
};
|
||||
expect(getParameterDisplayValue(expr)).toBe('Variables.count');
|
||||
});
|
||||
|
||||
it('returns value as-is for simple values', () => {
|
||||
expect(getParameterDisplayValue(42)).toBe(42);
|
||||
expect(getParameterDisplayValue('hello')).toBe('hello');
|
||||
expect(getParameterDisplayValue(true)).toBe(true);
|
||||
expect(getParameterDisplayValue(null)).toBe(null);
|
||||
expect(getParameterDisplayValue(undefined)).toBe(undefined);
|
||||
});
|
||||
|
||||
it('returns value as-is for objects', () => {
|
||||
const obj = { a: 1, b: 2 };
|
||||
expect(getParameterDisplayValue(obj)).toBe(obj);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getParameterActualValue', () => {
|
||||
it('returns fallback for expression parameters', () => {
|
||||
const expr: ExpressionParameter = {
|
||||
mode: 'expression',
|
||||
expression: 'Variables.x * 2',
|
||||
fallback: 100
|
||||
};
|
||||
expect(getParameterActualValue(expr)).toBe(100);
|
||||
});
|
||||
|
||||
it('returns undefined for expression without fallback', () => {
|
||||
const expr: ExpressionParameter = {
|
||||
mode: 'expression',
|
||||
expression: 'Variables.x'
|
||||
};
|
||||
expect(getParameterActualValue(expr)).toBeUndefined();
|
||||
});
|
||||
|
||||
it('returns value as-is for simple values', () => {
|
||||
expect(getParameterActualValue(42)).toBe(42);
|
||||
expect(getParameterActualValue('hello')).toBe('hello');
|
||||
expect(getParameterActualValue(false)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('createExpressionParameter', () => {
|
||||
it('creates expression parameter with all fields', () => {
|
||||
const expr = createExpressionParameter('Variables.count', 0, 2);
|
||||
expect(expr.mode).toBe('expression');
|
||||
expect(expr.expression).toBe('Variables.count');
|
||||
expect(expr.fallback).toBe(0);
|
||||
expect(expr.version).toBe(2);
|
||||
});
|
||||
|
||||
it('uses default version if not provided', () => {
|
||||
const expr = createExpressionParameter('Variables.x', 10);
|
||||
expect(expr.version).toBe(1);
|
||||
});
|
||||
|
||||
it('allows undefined fallback', () => {
|
||||
const expr = createExpressionParameter('Variables.x');
|
||||
expect(expr.fallback).toBeUndefined();
|
||||
expect(expr.version).toBe(1);
|
||||
});
|
||||
|
||||
it('allows null fallback', () => {
|
||||
const expr = createExpressionParameter('Variables.x', null);
|
||||
expect(expr.fallback).toBe(null);
|
||||
});
|
||||
|
||||
it('allows zero as fallback', () => {
|
||||
const expr = createExpressionParameter('Variables.x', 0);
|
||||
expect(expr.fallback).toBe(0);
|
||||
});
|
||||
|
||||
it('allows empty string as fallback', () => {
|
||||
const expr = createExpressionParameter('Variables.x', '');
|
||||
expect(expr.fallback).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('toParameter', () => {
|
||||
it('passes through expression parameters', () => {
|
||||
const expr: ExpressionParameter = {
|
||||
mode: 'expression',
|
||||
expression: 'Variables.x',
|
||||
fallback: 0
|
||||
};
|
||||
expect(toParameter(expr)).toBe(expr);
|
||||
});
|
||||
|
||||
it('returns simple values as-is', () => {
|
||||
expect(toParameter(42)).toBe(42);
|
||||
expect(toParameter('hello')).toBe('hello');
|
||||
expect(toParameter(true)).toBe(true);
|
||||
expect(toParameter(null)).toBe(null);
|
||||
expect(toParameter(undefined)).toBe(undefined);
|
||||
});
|
||||
|
||||
it('returns objects as-is', () => {
|
||||
const obj = { a: 1 };
|
||||
expect(toParameter(obj)).toBe(obj);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Serialization', () => {
|
||||
it('expression parameters serialize to JSON correctly', () => {
|
||||
const expr = createExpressionParameter('Variables.count', 10);
|
||||
const json = JSON.stringify(expr);
|
||||
const parsed = JSON.parse(json);
|
||||
|
||||
expect(parsed.mode).toBe('expression');
|
||||
expect(parsed.expression).toBe('Variables.count');
|
||||
expect(parsed.fallback).toBe(10);
|
||||
expect(parsed.version).toBe(1);
|
||||
});
|
||||
|
||||
it('deserialized expression parameters are recognized', () => {
|
||||
const json = '{"mode":"expression","expression":"Variables.x","fallback":0,"version":1}';
|
||||
const parsed = JSON.parse(json);
|
||||
|
||||
expect(isExpressionParameter(parsed)).toBe(true);
|
||||
expect(parsed.expression).toBe('Variables.x');
|
||||
expect(parsed.fallback).toBe(0);
|
||||
});
|
||||
|
||||
it('handles undefined fallback in serialization', () => {
|
||||
const expr = createExpressionParameter('Variables.x');
|
||||
const json = JSON.stringify(expr);
|
||||
const parsed = JSON.parse(json);
|
||||
|
||||
expect(parsed.fallback).toBeUndefined();
|
||||
expect(isExpressionParameter(parsed)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Backward Compatibility', () => {
|
||||
it('simple values in parameters object work', () => {
|
||||
const params = {
|
||||
marginLeft: 16,
|
||||
color: '#ff0000',
|
||||
enabled: true
|
||||
};
|
||||
|
||||
expect(isExpressionParameter(params.marginLeft)).toBe(false);
|
||||
expect(isExpressionParameter(params.color)).toBe(false);
|
||||
expect(isExpressionParameter(params.enabled)).toBe(false);
|
||||
});
|
||||
|
||||
it('mixed parameters work', () => {
|
||||
const params = {
|
||||
marginLeft: createExpressionParameter('Variables.spacing', 16),
|
||||
marginRight: 8, // Simple value
|
||||
color: '#ff0000'
|
||||
};
|
||||
|
||||
expect(isExpressionParameter(params.marginLeft)).toBe(true);
|
||||
expect(isExpressionParameter(params.marginRight)).toBe(false);
|
||||
expect(isExpressionParameter(params.color)).toBe(false);
|
||||
});
|
||||
|
||||
it('old project parameters load correctly', () => {
|
||||
// Simulating loading old project
|
||||
const oldParams = {
|
||||
width: 200,
|
||||
height: 100,
|
||||
text: 'Hello'
|
||||
};
|
||||
|
||||
// None should be expressions
|
||||
Object.values(oldParams).forEach((value) => {
|
||||
expect(isExpressionParameter(value)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
it('new project with expressions loads correctly', () => {
|
||||
const newParams = {
|
||||
width: createExpressionParameter('Variables.width', 200),
|
||||
height: 100, // Mixed: some expression, some not
|
||||
text: 'Static text'
|
||||
};
|
||||
|
||||
expect(isExpressionParameter(newParams.width)).toBe(true);
|
||||
expect(isExpressionParameter(newParams.height)).toBe(false);
|
||||
expect(isExpressionParameter(newParams.text)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Edge Cases', () => {
|
||||
it('handles complex expressions', () => {
|
||||
const expr = createExpressionParameter('Variables.isAdmin ? "Admin Panel" : "User Panel"', 'User Panel');
|
||||
expect(expr.expression).toBe('Variables.isAdmin ? "Admin Panel" : "User Panel"');
|
||||
});
|
||||
|
||||
it('handles multi-line expressions', () => {
|
||||
const multiLine = `Variables.items
|
||||
.filter(x => x.active)
|
||||
.length`;
|
||||
const expr = createExpressionParameter(multiLine, 0);
|
||||
expect(expr.expression).toBe(multiLine);
|
||||
});
|
||||
|
||||
it('handles expressions with special characters', () => {
|
||||
const expr = createExpressionParameter('Variables["my-variable"]', null);
|
||||
expect(expr.expression).toBe('Variables["my-variable"]');
|
||||
});
|
||||
});
|
||||
});
|
||||
387
packages/noodl-editor/tests/utils/ParameterValueResolver.test.ts
Normal file
387
packages/noodl-editor/tests/utils/ParameterValueResolver.test.ts
Normal file
@@ -0,0 +1,387 @@
|
||||
/**
|
||||
* Unit tests for ParameterValueResolver
|
||||
*
|
||||
* Tests the resolution of parameter values from storage (primitives or expression objects)
|
||||
* to display/runtime values based on context.
|
||||
*
|
||||
* @module noodl-editor/tests/utils
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from '@jest/globals';
|
||||
|
||||
import { createExpressionParameter, ExpressionParameter } from '../../src/editor/src/models/ExpressionParameter';
|
||||
import { ParameterValueResolver, ValueContext } from '../../src/editor/src/utils/ParameterValueResolver';
|
||||
|
||||
describe('ParameterValueResolver', () => {
|
||||
describe('resolve()', () => {
|
||||
describe('with primitive values', () => {
|
||||
it('should return string values as-is', () => {
|
||||
expect(ParameterValueResolver.resolve('hello', ValueContext.Display)).toBe('hello');
|
||||
expect(ParameterValueResolver.resolve('', ValueContext.Display)).toBe('');
|
||||
expect(ParameterValueResolver.resolve('123', ValueContext.Display)).toBe('123');
|
||||
});
|
||||
|
||||
it('should return number values as-is', () => {
|
||||
expect(ParameterValueResolver.resolve(42, ValueContext.Display)).toBe(42);
|
||||
expect(ParameterValueResolver.resolve(0, ValueContext.Display)).toBe(0);
|
||||
expect(ParameterValueResolver.resolve(-42.5, ValueContext.Display)).toBe(-42.5);
|
||||
});
|
||||
|
||||
it('should return boolean values as-is', () => {
|
||||
expect(ParameterValueResolver.resolve(true, ValueContext.Display)).toBe(true);
|
||||
expect(ParameterValueResolver.resolve(false, ValueContext.Display)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return undefined as-is', () => {
|
||||
expect(ParameterValueResolver.resolve(undefined, ValueContext.Display)).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should handle null', () => {
|
||||
expect(ParameterValueResolver.resolve(null, ValueContext.Display)).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with expression parameters', () => {
|
||||
it('should extract fallback from expression parameter in Display context', () => {
|
||||
const exprParam = createExpressionParameter('Variables.x', 'default', 1);
|
||||
expect(ParameterValueResolver.resolve(exprParam, ValueContext.Display)).toBe('default');
|
||||
});
|
||||
|
||||
it('should extract fallback from expression parameter in Runtime context', () => {
|
||||
const exprParam = createExpressionParameter('Variables.x', 'default', 1);
|
||||
expect(ParameterValueResolver.resolve(exprParam, ValueContext.Runtime)).toBe('default');
|
||||
});
|
||||
|
||||
it('should return full object in Serialization context', () => {
|
||||
const exprParam = createExpressionParameter('Variables.x', 'default', 1);
|
||||
const result = ParameterValueResolver.resolve(exprParam, ValueContext.Serialization);
|
||||
expect(result).toBe(exprParam);
|
||||
expect((result as ExpressionParameter).mode).toBe('expression');
|
||||
});
|
||||
|
||||
it('should handle expression parameter with undefined fallback', () => {
|
||||
const exprParam = createExpressionParameter('Variables.x', undefined, 1);
|
||||
expect(ParameterValueResolver.resolve(exprParam, ValueContext.Display)).toBe('');
|
||||
});
|
||||
|
||||
it('should handle expression parameter with numeric fallback', () => {
|
||||
const exprParam = createExpressionParameter('Variables.count', 42, 1);
|
||||
expect(ParameterValueResolver.resolve(exprParam, ValueContext.Display)).toBe(42);
|
||||
});
|
||||
|
||||
it('should handle expression parameter with boolean fallback', () => {
|
||||
const exprParam = createExpressionParameter('Variables.flag', true, 1);
|
||||
expect(ParameterValueResolver.resolve(exprParam, ValueContext.Display)).toBe(true);
|
||||
});
|
||||
|
||||
it('should handle expression parameter with empty string fallback', () => {
|
||||
const exprParam = createExpressionParameter('Variables.x', '', 1);
|
||||
expect(ParameterValueResolver.resolve(exprParam, ValueContext.Display)).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('edge cases', () => {
|
||||
it('should handle objects that are not expression parameters', () => {
|
||||
const regularObj = { foo: 'bar' };
|
||||
// Should return as-is since it's not an expression parameter
|
||||
expect(ParameterValueResolver.resolve(regularObj, ValueContext.Display)).toBe(regularObj);
|
||||
});
|
||||
|
||||
it('should default to fallback for unknown context', () => {
|
||||
const exprParam = createExpressionParameter('Variables.x', 'default', 1);
|
||||
// Cast to any to test invalid context
|
||||
expect(ParameterValueResolver.resolve(exprParam, 'invalid' as any)).toBe('default');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('toString()', () => {
|
||||
describe('with primitive values', () => {
|
||||
it('should convert string to string', () => {
|
||||
expect(ParameterValueResolver.toString('hello')).toBe('hello');
|
||||
expect(ParameterValueResolver.toString('')).toBe('');
|
||||
});
|
||||
|
||||
it('should convert number to string', () => {
|
||||
expect(ParameterValueResolver.toString(42)).toBe('42');
|
||||
expect(ParameterValueResolver.toString(0)).toBe('0');
|
||||
expect(ParameterValueResolver.toString(-42.5)).toBe('-42.5');
|
||||
});
|
||||
|
||||
it('should convert boolean to string', () => {
|
||||
expect(ParameterValueResolver.toString(true)).toBe('true');
|
||||
expect(ParameterValueResolver.toString(false)).toBe('false');
|
||||
});
|
||||
|
||||
it('should convert undefined to empty string', () => {
|
||||
expect(ParameterValueResolver.toString(undefined)).toBe('');
|
||||
});
|
||||
|
||||
it('should convert null to empty string', () => {
|
||||
expect(ParameterValueResolver.toString(null)).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('with expression parameters', () => {
|
||||
it('should extract fallback as string from expression parameter', () => {
|
||||
const exprParam = createExpressionParameter('Variables.x', 'test', 1);
|
||||
expect(ParameterValueResolver.toString(exprParam)).toBe('test');
|
||||
});
|
||||
|
||||
it('should convert numeric fallback to string', () => {
|
||||
const exprParam = createExpressionParameter('Variables.count', 42, 1);
|
||||
expect(ParameterValueResolver.toString(exprParam)).toBe('42');
|
||||
});
|
||||
|
||||
it('should convert boolean fallback to string', () => {
|
||||
const exprParam = createExpressionParameter('Variables.flag', true, 1);
|
||||
expect(ParameterValueResolver.toString(exprParam)).toBe('true');
|
||||
});
|
||||
|
||||
it('should handle expression parameter with undefined fallback', () => {
|
||||
const exprParam = createExpressionParameter('Variables.x', undefined, 1);
|
||||
expect(ParameterValueResolver.toString(exprParam)).toBe('');
|
||||
});
|
||||
|
||||
it('should handle expression parameter with null fallback', () => {
|
||||
const exprParam = createExpressionParameter('Variables.x', null, 1);
|
||||
expect(ParameterValueResolver.toString(exprParam)).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('edge cases', () => {
|
||||
it('should handle objects that are not expression parameters', () => {
|
||||
const regularObj = { foo: 'bar' };
|
||||
// Should return empty string for safety (defensive behavior)
|
||||
expect(ParameterValueResolver.toString(regularObj)).toBe('');
|
||||
});
|
||||
|
||||
it('should handle arrays', () => {
|
||||
expect(ParameterValueResolver.toString([1, 2, 3])).toBe('');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('toNumber()', () => {
|
||||
describe('with primitive values', () => {
|
||||
it('should return number as-is', () => {
|
||||
expect(ParameterValueResolver.toNumber(42)).toBe(42);
|
||||
expect(ParameterValueResolver.toNumber(0)).toBe(0);
|
||||
expect(ParameterValueResolver.toNumber(-42.5)).toBe(-42.5);
|
||||
});
|
||||
|
||||
it('should convert numeric string to number', () => {
|
||||
expect(ParameterValueResolver.toNumber('42')).toBe(42);
|
||||
expect(ParameterValueResolver.toNumber('0')).toBe(0);
|
||||
expect(ParameterValueResolver.toNumber('-42.5')).toBe(-42.5);
|
||||
});
|
||||
|
||||
it('should return undefined for non-numeric string', () => {
|
||||
expect(ParameterValueResolver.toNumber('hello')).toBe(undefined);
|
||||
expect(ParameterValueResolver.toNumber('not a number')).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should return undefined for undefined', () => {
|
||||
expect(ParameterValueResolver.toNumber(undefined)).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should return undefined for null', () => {
|
||||
expect(ParameterValueResolver.toNumber(null)).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should convert boolean to number', () => {
|
||||
expect(ParameterValueResolver.toNumber(true)).toBe(1);
|
||||
expect(ParameterValueResolver.toNumber(false)).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with expression parameters', () => {
|
||||
it('should extract numeric fallback from expression parameter', () => {
|
||||
const exprParam = createExpressionParameter('Variables.count', 42, 1);
|
||||
expect(ParameterValueResolver.toNumber(exprParam)).toBe(42);
|
||||
});
|
||||
|
||||
it('should convert string fallback to number', () => {
|
||||
const exprParam = createExpressionParameter('Variables.count', '42', 1);
|
||||
expect(ParameterValueResolver.toNumber(exprParam)).toBe(42);
|
||||
});
|
||||
|
||||
it('should return undefined for non-numeric fallback', () => {
|
||||
const exprParam = createExpressionParameter('Variables.text', 'hello', 1);
|
||||
expect(ParameterValueResolver.toNumber(exprParam)).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should handle expression parameter with undefined fallback', () => {
|
||||
const exprParam = createExpressionParameter('Variables.x', undefined, 1);
|
||||
expect(ParameterValueResolver.toNumber(exprParam)).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should handle expression parameter with null fallback', () => {
|
||||
const exprParam = createExpressionParameter('Variables.x', null, 1);
|
||||
expect(ParameterValueResolver.toNumber(exprParam)).toBe(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('edge cases', () => {
|
||||
it('should handle objects that are not expression parameters', () => {
|
||||
const regularObj = { foo: 'bar' };
|
||||
expect(ParameterValueResolver.toNumber(regularObj)).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should handle arrays', () => {
|
||||
expect(ParameterValueResolver.toNumber([1, 2, 3])).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should handle empty string', () => {
|
||||
expect(ParameterValueResolver.toNumber('')).toBe(0); // Empty string converts to 0
|
||||
});
|
||||
|
||||
it('should handle whitespace string', () => {
|
||||
expect(ParameterValueResolver.toNumber(' ')).toBe(0); // Whitespace converts to 0
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('toBoolean()', () => {
|
||||
describe('with primitive values', () => {
|
||||
it('should return boolean as-is', () => {
|
||||
expect(ParameterValueResolver.toBoolean(true)).toBe(true);
|
||||
expect(ParameterValueResolver.toBoolean(false)).toBe(false);
|
||||
});
|
||||
|
||||
it('should convert truthy strings to true', () => {
|
||||
expect(ParameterValueResolver.toBoolean('hello')).toBe(true);
|
||||
expect(ParameterValueResolver.toBoolean('0')).toBe(true); // Non-empty string is truthy
|
||||
expect(ParameterValueResolver.toBoolean('false')).toBe(true); // Non-empty string is truthy
|
||||
});
|
||||
|
||||
it('should convert empty string to false', () => {
|
||||
expect(ParameterValueResolver.toBoolean('')).toBe(false);
|
||||
});
|
||||
|
||||
it('should convert numbers using truthiness', () => {
|
||||
expect(ParameterValueResolver.toBoolean(1)).toBe(true);
|
||||
expect(ParameterValueResolver.toBoolean(42)).toBe(true);
|
||||
expect(ParameterValueResolver.toBoolean(0)).toBe(false);
|
||||
expect(ParameterValueResolver.toBoolean(-1)).toBe(true);
|
||||
});
|
||||
|
||||
it('should convert undefined to false', () => {
|
||||
expect(ParameterValueResolver.toBoolean(undefined)).toBe(false);
|
||||
});
|
||||
|
||||
it('should convert null to false', () => {
|
||||
expect(ParameterValueResolver.toBoolean(null)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with expression parameters', () => {
|
||||
it('should extract boolean fallback from expression parameter', () => {
|
||||
const exprParam = createExpressionParameter('Variables.flag', true, 1);
|
||||
expect(ParameterValueResolver.toBoolean(exprParam)).toBe(true);
|
||||
});
|
||||
|
||||
it('should convert string fallback to boolean', () => {
|
||||
const exprParamTruthy = createExpressionParameter('Variables.text', 'hello', 1);
|
||||
expect(ParameterValueResolver.toBoolean(exprParamTruthy)).toBe(true);
|
||||
|
||||
const exprParamFalsy = createExpressionParameter('Variables.text', '', 1);
|
||||
expect(ParameterValueResolver.toBoolean(exprParamFalsy)).toBe(false);
|
||||
});
|
||||
|
||||
it('should convert numeric fallback to boolean', () => {
|
||||
const exprParamTruthy = createExpressionParameter('Variables.count', 42, 1);
|
||||
expect(ParameterValueResolver.toBoolean(exprParamTruthy)).toBe(true);
|
||||
|
||||
const exprParamFalsy = createExpressionParameter('Variables.count', 0, 1);
|
||||
expect(ParameterValueResolver.toBoolean(exprParamFalsy)).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle expression parameter with undefined fallback', () => {
|
||||
const exprParam = createExpressionParameter('Variables.x', undefined, 1);
|
||||
expect(ParameterValueResolver.toBoolean(exprParam)).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle expression parameter with null fallback', () => {
|
||||
const exprParam = createExpressionParameter('Variables.x', null, 1);
|
||||
expect(ParameterValueResolver.toBoolean(exprParam)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('edge cases', () => {
|
||||
it('should handle objects that are not expression parameters', () => {
|
||||
const regularObj = { foo: 'bar' };
|
||||
// Non-expression objects should return false (defensive behavior)
|
||||
expect(ParameterValueResolver.toBoolean(regularObj)).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle arrays', () => {
|
||||
expect(ParameterValueResolver.toBoolean([1, 2, 3])).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('isExpression()', () => {
|
||||
it('should return true for expression parameters', () => {
|
||||
const exprParam = createExpressionParameter('Variables.x', 'default', 1);
|
||||
expect(ParameterValueResolver.isExpression(exprParam)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for primitive values', () => {
|
||||
expect(ParameterValueResolver.isExpression('hello')).toBe(false);
|
||||
expect(ParameterValueResolver.isExpression(42)).toBe(false);
|
||||
expect(ParameterValueResolver.isExpression(true)).toBe(false);
|
||||
expect(ParameterValueResolver.isExpression(undefined)).toBe(false);
|
||||
expect(ParameterValueResolver.isExpression(null)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false for regular objects', () => {
|
||||
const regularObj = { foo: 'bar' };
|
||||
expect(ParameterValueResolver.isExpression(regularObj)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false for arrays', () => {
|
||||
expect(ParameterValueResolver.isExpression([1, 2, 3])).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('integration scenarios', () => {
|
||||
it('should handle converting expression parameter through all type conversions', () => {
|
||||
const exprParam = createExpressionParameter('Variables.count', 42, 1);
|
||||
|
||||
expect(ParameterValueResolver.toString(exprParam)).toBe('42');
|
||||
expect(ParameterValueResolver.toNumber(exprParam)).toBe(42);
|
||||
expect(ParameterValueResolver.toBoolean(exprParam)).toBe(true);
|
||||
expect(ParameterValueResolver.isExpression(exprParam)).toBe(true);
|
||||
});
|
||||
|
||||
it('should handle canvas rendering scenario (text.split prevention)', () => {
|
||||
// This is the actual bug we're fixing - canvas tries to call .split() on a parameter
|
||||
const exprParam = createExpressionParameter('Variables.text', 'Hello\nWorld', 1);
|
||||
|
||||
// Before fix: this would return the object, causing text.split() to crash
|
||||
// After fix: this returns a string that can be safely split
|
||||
const text = ParameterValueResolver.toString(exprParam);
|
||||
expect(typeof text).toBe('string');
|
||||
expect(() => text.split('\n')).not.toThrow();
|
||||
expect(text.split('\n')).toEqual(['Hello', 'World']);
|
||||
});
|
||||
|
||||
it('should handle property panel display scenario', () => {
|
||||
// Property panel needs to show fallback value while user edits expression
|
||||
const exprParam = createExpressionParameter('2 + 2', '4', 1);
|
||||
|
||||
const displayValue = ParameterValueResolver.resolve(exprParam, ValueContext.Display);
|
||||
expect(displayValue).toBe('4');
|
||||
});
|
||||
|
||||
it('should handle serialization scenario', () => {
|
||||
// When saving, we need the full object preserved
|
||||
const exprParam = createExpressionParameter('Variables.x', 'default', 1);
|
||||
|
||||
const serialized = ParameterValueResolver.resolve(exprParam, ValueContext.Serialization);
|
||||
expect(serialized).toBe(exprParam);
|
||||
expect((serialized as ExpressionParameter).expression).toBe('Variables.x');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1 +1,2 @@
|
||||
export * from './ParameterValueResolver.test';
|
||||
export * from './verify-json.spec';
|
||||
|
||||
Reference in New Issue
Block a user