diff --git a/src/modules/Elsa.Expressions.JavaScript/Handlers/ConfigureEngineWithVariableTypes.cs b/src/modules/Elsa.Expressions.JavaScript/Handlers/ConfigureEngineWithVariableTypes.cs index 4b52a254d..29abe6f5a 100644 --- a/src/modules/Elsa.Expressions.JavaScript/Handlers/ConfigureEngineWithVariableTypes.cs +++ b/src/modules/Elsa.Expressions.JavaScript/Handlers/ConfigureEngineWithVariableTypes.cs @@ -11,12 +11,19 @@ namespace Elsa.Expressions.JavaScript.Handlers; public class ConfigureEngineWithWorkflowVariableTypes(IOptions options) : INotificationHandler { + private static readonly Type[] BlacklistedTypes = + [ + typeof(string), + typeof(object), + // Add more types if needed. + ]; + /// public Task HandleAsync(EvaluatingJavaScript notification, CancellationToken cancellationToken) { var engine = notification.Engine; var variableTypes = options.Value.VariableDescriptors - .Where(x => x.Type is { ContainsGenericParameters: false} && x.Type != typeof(object)) + .Where(x => x.Type is { ContainsGenericParameters: false } && !BlacklistedTypes.Contains(x.Type) && !x.Type.IsPrimitive) .Select(x => x.Type) .ToArray(); diff --git a/test/integration/Elsa.JavaScript.IntegrationTests/JavaScriptAndNetTypeTest.cs b/test/integration/Elsa.JavaScript.IntegrationTests/JavaScriptAndNetTypeTest.cs new file mode 100644 index 000000000..3858ead2a --- /dev/null +++ b/test/integration/Elsa.JavaScript.IntegrationTests/JavaScriptAndNetTypeTest.cs @@ -0,0 +1,71 @@ +using System.Dynamic; +using System.Numerics; +using System.Text.Json; +using Elsa.Common.Converters; +using Elsa.Expressions.Models; +using Elsa.JavaScript.Contracts; +using Elsa.Testing.Shared; +using Microsoft.Extensions.DependencyInjection; +using Xunit; +using Xunit.Abstractions; + +namespace Elsa.JavaScript.IntegrationTests; + +/// +/// These tests ensure that we did not replace any JS types with .NET types. +/// +public class JavaScriptAndNetTypeTest +{ + private readonly IServiceProvider _serviceProvider; + private readonly IJavaScriptEvaluator _evaluator; + + public JavaScriptAndNetTypeTest(ITestOutputHelper testOutputHelper) + { + _serviceProvider = new TestApplicationBuilder(testOutputHelper).Build(); + _evaluator = _serviceProvider.GetRequiredService(); + } + + [Fact(DisplayName = "Can evaluate JavaScript that returns a string")] + public async Task ReturnsJsStringAsDotNetString() + { + var script = "return String('true')"; + var result = await EvaluateAsync(script); + + Assert.Equal("true", result); + } + + [Fact(DisplayName = "Can evaluate JavaScript that returns a string parsed into a Boolean")] + public async Task ReturnsJsStringParsedAsDotNetBoolean() + { + var script = "return String('true')"; + var result = await EvaluateAsync(script); + + Assert.True(result); + } + + [Fact(DisplayName = "Can evaluate JavaScript that constructs a JS Object")] + public async Task ReturnsJsObjectAsExpandoObject() + { + var script = "return Object({})"; + var result = await EvaluateAsync(script); + + Assert.NotNull(result); + Assert.IsType(result); + } + + [Fact(DisplayName = "Can evaluate JavaScript that returns a JS Array")] + public async Task ReturnsJsArrayAsDotNetArray() + { + var script = "return Array(1,2,3)"; + var result = await EvaluateAsync(script); + + Assert.NotNull(result); + } + + private async Task EvaluateAsync(string script) + { + var expressionExecutionContext = new ExpressionExecutionContext(_serviceProvider, new()); + var type = typeof(T); + return (T?)await _evaluator.EvaluateAsync(script, type, expressionExecutionContext); + } +}