Add integration test for reading composite activity output
This commit is contained in:
parent
0e992a9cbd
commit
cebf6f12e3
|
|
@ -1,4 +1,5 @@
|
|||
using Elsa.Extensions;
|
||||
using Elsa.Features.Services;
|
||||
using Elsa.Workflows.Core.Contracts;
|
||||
using Elsa.Workflows.Core.Services;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
|
@ -11,26 +12,36 @@ public class TestApplicationBuilder
|
|||
{
|
||||
private readonly ITestOutputHelper _testOutputHelper;
|
||||
private readonly ServiceCollection _services;
|
||||
private Action<IModule> _configureElsa;
|
||||
|
||||
public TestApplicationBuilder(ITestOutputHelper testOutputHelper)
|
||||
{
|
||||
_testOutputHelper = testOutputHelper;
|
||||
_services = new ServiceCollection();
|
||||
|
||||
_services.AddElsa(elsa => elsa
|
||||
.UseWorkflows(workflows => workflows
|
||||
.WithStandardOutStreamProvider(_ => new StandardOutStreamProvider(new XunitConsoleTextWriter(testOutputHelper)))
|
||||
)
|
||||
);
|
||||
|
||||
_services
|
||||
.AddSingleton(testOutputHelper)
|
||||
.AddLogging(logging => logging.AddProvider(new XunitLoggerProvider(testOutputHelper)).SetMinimumLevel(LogLevel.Debug));
|
||||
|
||||
_configureElsa += elsa => elsa
|
||||
.UseWorkflows(workflows => workflows
|
||||
.WithStandardOutStreamProvider(_ => new StandardOutStreamProvider(new XunitConsoleTextWriter(_testOutputHelper)))
|
||||
);
|
||||
}
|
||||
|
||||
public IServiceProvider Build() => _services.BuildServiceProvider();
|
||||
public IServiceProvider Build()
|
||||
{
|
||||
_services.AddElsa(_configureElsa);
|
||||
return _services.BuildServiceProvider();
|
||||
}
|
||||
|
||||
public TestApplicationBuilder Configure(Action<IServiceCollection> configure)
|
||||
public TestApplicationBuilder ConfigureElsa(Action<IModule> configure)
|
||||
{
|
||||
_configureElsa += configure;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TestApplicationBuilder ConfigureServices(Action<IServiceCollection> configure)
|
||||
{
|
||||
configure(_services);
|
||||
return this;
|
||||
|
|
@ -39,7 +50,9 @@ public class TestApplicationBuilder
|
|||
public TestApplicationBuilder WithCapturingTextWriter(CapturingTextWriter capturingTextWriter)
|
||||
{
|
||||
var combinedTextWriter = new CombinedTextWriter(capturingTextWriter, new XunitConsoleTextWriter(_testOutputHelper));
|
||||
_services.AddSingleton<IStandardOutStreamProvider>(new StandardOutStreamProvider(combinedTextWriter));
|
||||
var provider = new StandardOutStreamProvider(combinedTextWriter);
|
||||
|
||||
ConfigureElsa(elsa => elsa.UseWorkflows(workflows => workflows.WithStandardOutStreamProvider(_ => provider)));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
@ -65,8 +65,8 @@ public class JintJavaScriptEvaluator : IJavaScriptEvaluator
|
|||
engine.SetValue("getVariable", (Func<string, object?>)(id => context.GetVariable(id)));
|
||||
engine.SetValue("getInput", (Func<string, object?>)(name => context.GetWorkflowExecutionContext().Input.GetValue(name)));
|
||||
|
||||
// Create variable & input setters and getters for each variable.
|
||||
CreateMemoryBlockAccessors(engine, context);
|
||||
// Create variable getters and setters for each variable.
|
||||
CreateVariableAccessors(engine, context);
|
||||
|
||||
engine.SetValue("isNullOrWhiteSpace", (Func<string, bool>)(value => string.IsNullOrWhiteSpace(value)));
|
||||
engine.SetValue("isNullOrEmpty", (Func<string, bool>)(value => string.IsNullOrEmpty(value)));
|
||||
|
|
@ -88,7 +88,7 @@ public class JintJavaScriptEvaluator : IJavaScriptEvaluator
|
|||
return engine;
|
||||
}
|
||||
|
||||
private static void CreateMemoryBlockAccessors(Engine engine, ExpressionExecutionContext context)
|
||||
private static void CreateVariableAccessors(Engine engine, ExpressionExecutionContext context)
|
||||
{
|
||||
var variableNames = GetVariableNamesInScope(context).ToList();
|
||||
|
||||
|
|
@ -100,7 +100,11 @@ public class JintJavaScriptEvaluator : IJavaScriptEvaluator
|
|||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<string> GetVariableNamesInScope(ExpressionExecutionContext context) => EnumerateVariablesInScope(context).Select(x => x.Name).Distinct();
|
||||
private static IEnumerable<string> GetVariableNamesInScope(ExpressionExecutionContext context) =>
|
||||
EnumerateVariablesInScope(context)
|
||||
.Select(x => x.Name)
|
||||
.Where(x => !string.IsNullOrWhiteSpace(x))
|
||||
.Distinct();
|
||||
|
||||
private static object GetVariableInScope(ExpressionExecutionContext context, string variableName)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -48,10 +48,11 @@ public abstract class Composite : Activity, IVariableContainer
|
|||
/// <inheritdoc />
|
||||
protected override async ValueTask ExecuteAsync(ActivityExecutionContext context)
|
||||
{
|
||||
ConfigureActivities(context);
|
||||
|
||||
// Register variables.
|
||||
context.ExpressionExecutionContext.Memory.Declare(Variables);
|
||||
|
||||
ConfigureActivities(context);
|
||||
await context.ScheduleActivityAsync(Root, OnRootCompletedAsync);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,12 @@ public class Variable<T> : Variable
|
|||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public Variable(string name, T value)
|
||||
{
|
||||
Name = name;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public T? Get(ActivityExecutionContext context) => Get(context.ExpressionExecutionContext).ConvertTo<T?>();
|
||||
public new T? Get(ExpressionExecutionContext context) => base.Get(context).ConvertTo<T?>();
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\common\Elsa.Testing.Shared\Elsa.Testing.Shared.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\modules\Elsa.JavaScript\Elsa.JavaScript.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\modules\Elsa.Workflows.Runtime\Elsa.Workflows.Runtime.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Testing.Shared;
|
||||
using Elsa.Workflows.Core.Contracts;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Elsa.IntegrationTests.Scenarios.Composites;
|
||||
|
||||
public class Tests
|
||||
{
|
||||
private readonly IWorkflowRunner _workflowRunner;
|
||||
private readonly CapturingTextWriter _capturingTextWriter = new();
|
||||
private readonly IWorkflowBuilderFactory _workflowBuilderFactory;
|
||||
|
||||
public Tests(ITestOutputHelper testOutputHelper)
|
||||
{
|
||||
var services = new TestApplicationBuilder(testOutputHelper)
|
||||
.WithCapturingTextWriter(_capturingTextWriter)
|
||||
.ConfigureElsa(elsa => elsa.UseJavaScript())
|
||||
.Build();
|
||||
_workflowBuilderFactory = services.GetRequiredService<IWorkflowBuilderFactory>();
|
||||
_workflowRunner = services.GetRequiredService<IWorkflowRunner>();
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "The main workflow can capture the result of the composite activity")]
|
||||
public async Task Test1()
|
||||
{
|
||||
var workflow = await _workflowBuilderFactory.CreateBuilder().BuildWorkflowAsync<SumWorkflow>();
|
||||
|
||||
// Start workflow.
|
||||
await _workflowRunner.RunAsync(workflow);
|
||||
|
||||
// Verify expected output.
|
||||
var lines = _capturingTextWriter.Lines.ToList();
|
||||
Assert.Equal(new[] { "Sum: 3" }, lines);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
using Elsa.Extensions;
|
||||
using Elsa.JavaScript.Activities;
|
||||
using Elsa.Workflows.Core.Abstractions;
|
||||
using Elsa.Workflows.Core.Activities;
|
||||
using Elsa.Workflows.Core.Contracts;
|
||||
using Elsa.Workflows.Core.Models;
|
||||
|
||||
namespace Elsa.IntegrationTests.Scenarios.Composites;
|
||||
|
||||
/// <summary>
|
||||
/// A composite activity that sums two inputs and returns the result.
|
||||
/// </summary>
|
||||
public class Sum : Composite<int>
|
||||
{
|
||||
private readonly RunJavaScript _runJavaScript;
|
||||
|
||||
public Input<int> A { get; set; } = default!;
|
||||
public Input<int> B { get; set; } = default!;
|
||||
|
||||
public Sum()
|
||||
{
|
||||
_runJavaScript = new RunJavaScript
|
||||
{
|
||||
Script = new("getA() + getB();"),
|
||||
};
|
||||
|
||||
Root = new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
_runJavaScript
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void ConfigureActivities(ActivityExecutionContext context)
|
||||
{
|
||||
// Copy input into variables so that JS activity can access them.
|
||||
var a = A.Get(context);
|
||||
var b = B.Get(context);
|
||||
Variables.Add(new Variable<int>("A", a));
|
||||
Variables.Add(new Variable<int>("B", b));
|
||||
|
||||
// If the call site set a result variable, assign it to the JavaScript activity's result.
|
||||
if (Result != null)
|
||||
_runJavaScript.Result = new Output<object>(Result.MemoryBlockReference)!;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A workflow that uses the <see cref="Sum"/> composite activity.
|
||||
/// </summary>
|
||||
public class SumWorkflow : WorkflowBase
|
||||
{
|
||||
protected override void Build(IWorkflowBuilder workflow)
|
||||
{
|
||||
var sum = new Variable<int>();
|
||||
|
||||
workflow.Root = new Sequence
|
||||
{
|
||||
Variables = { sum },
|
||||
Activities =
|
||||
{
|
||||
new Sum
|
||||
{
|
||||
A = new(1),
|
||||
B = new(2),
|
||||
Result = new(sum)
|
||||
},
|
||||
new WriteLine(context => $"Sum: {sum.Get(context)}")
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue