using Elsa.Expressions.JavaScript.Contracts; using Elsa.Expressions.Models; using Elsa.Testing.Shared; using Microsoft.Extensions.DependencyInjection; using Xunit; using Xunit.Abstractions; namespace Elsa.JavaScript.IntegrationTests; /// /// Verifies the behaviour of the prepared-script cache. /// public class ScriptCacheTests { private readonly IServiceProvider _serviceProvider; private readonly IJavaScriptEvaluator _evaluator; public ScriptCacheTests(ITestOutputHelper testOutputHelper) { _serviceProvider = new TestApplicationBuilder(testOutputHelper).Build(); _evaluator = _serviceProvider.GetRequiredService(); } [Fact(DisplayName = "Repeated evaluation of the same expression produces the same result")] public async Task RepeatedEvaluationIsStable() { Assert.Equal("3", await EvaluateAsync("return '' + (1 + 2);")); Assert.Equal("3", await EvaluateAsync("return '' + (1 + 2);")); Assert.Equal("7", await EvaluateAsync("return '' + (3 + 4);")); Assert.Equal("3", await EvaluateAsync("return '' + (1 + 2);")); } [Fact(DisplayName = "An expression that fails to parse reports the failure on every evaluation")] public async Task ExpressionThatFailsToParseKeepsFailing() { var first = await Assert.ThrowsAnyAsync(() => EvaluateAsync("return (")); var second = await Assert.ThrowsAnyAsync(() => EvaluateAsync("return (")); // Every evaluation has to report the same parse failure. Merely throwing twice would also be satisfied // by a cache that stored a null or half-built entry for the failed preparation, because the second // evaluation would then fail too — just with a different exception. Comparing the two exceptions rules // that out. The script is identical on both evaluations, so any position the message carries is too. Assert.IsType(first.GetType(), second); Assert.Equal(first.Message, second.Message); } private async Task EvaluateAsync(string script) { var context = new ExpressionExecutionContext(_serviceProvider, new()); return (string?)await _evaluator.EvaluateAsync(script, typeof(string), context); } }