Add project files.

This commit is contained in:
2025-08-18 17:11:43 +03:30
parent 807dc263be
commit e5eb10d604
3943 changed files with 223719 additions and 0 deletions
@@ -0,0 +1,7 @@
namespace Elsa.Workflows.IntegrationTests.Scenarios.ActivityNotificationsMiddleware;
public class Spy
{
public bool ActivityExecutingWasCalled { get; set; }
public bool ActivityExecutedWasCalled { get; set; }
}
@@ -0,0 +1,26 @@
using Elsa.Mediator.Contracts;
using Elsa.Workflows.Notifications;
namespace Elsa.Workflows.IntegrationTests.Scenarios.ActivityNotificationsMiddleware;
public class TestHandler : INotificationHandler<ActivityExecuting>, INotificationHandler<ActivityExecuted>
{
private readonly Spy _spy;
public TestHandler(Spy spy)
{
_spy = spy;
}
public Task HandleAsync(ActivityExecuting notification, CancellationToken cancellationToken)
{
_spy.ActivityExecutingWasCalled = true;
return Task.CompletedTask;
}
public Task HandleAsync(ActivityExecuted notification, CancellationToken cancellationToken)
{
_spy.ActivityExecutedWasCalled = true;
return Task.CompletedTask;
}
}
@@ -0,0 +1,38 @@
using Elsa.Testing.Shared;
using Elsa.Workflows.Notifications;
using Microsoft.Extensions.DependencyInjection;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.ActivityNotificationsMiddleware;
public class Tests
{
private readonly IWorkflowRunner _workflowRunner;
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly Spy _spy;
public Tests(ITestOutputHelper testOutputHelper)
{
var services = new TestApplicationBuilder(testOutputHelper)
.WithCapturingTextWriter(_capturingTextWriter)
.ConfigureServices(s =>
{
s.AddSingleton<Spy>();
s.AddNotificationHandler<TestHandler, ActivityExecuting>();
s.AddNotificationHandler<TestHandler, ActivityExecuted>();
})
.Build();
_workflowRunner = services.GetRequiredService<IWorkflowRunner>();
_spy = services.GetRequiredService<Spy>();
}
[Fact(DisplayName = "Running workflow with activity notifications middleware results in notifications being published")]
public async Task Test1()
{
await _workflowRunner.RunAsync<HelloWorldWorkflow>();
Assert.True(_spy.ActivityExecutingWasCalled);
Assert.True(_spy.ActivityExecutedWasCalled);
}
}
@@ -0,0 +1,11 @@
using Elsa.Workflows.Activities;
namespace Elsa.Workflows.IntegrationTests.Scenarios.ActivityNotificationsMiddleware;
class HelloWorldWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder workflow)
{
workflow.Root = new WriteLine("Hello World!");
}
}
@@ -0,0 +1,34 @@
using Elsa.Extensions;
using Elsa.Workflows.Activities;
namespace Elsa.Workflows.IntegrationTests.Scenarios.ActivityOutputs;
public class LoopingWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder builder)
{
var readCurrentValue = new Inline<string>(context => context.GetVariable<string>("CurrentValue")!);
builder.Root = new ForEach<string>(
[
"Item 1",
"Item 2",
"Item 3"
])
{
Body = new Sequence
{
Activities =
[
readCurrentValue,
new WriteLine(context =>
{
var currentValue = context.GetVariable<string>("CurrentValue");
var activityResult = context.GetActivityExecutionContext().GetResult(readCurrentValue);
return $"Current value: {currentValue}, Activity result: {activityResult}";
})
]
}
};
}
}
@@ -0,0 +1,27 @@
using Elsa.Extensions;
using Elsa.Workflows.Memory;
using Elsa.Workflows.Models;
namespace Elsa.Workflows.IntegrationTests.Scenarios.ActivityOutputs;
public class SumActivity : CodeActivity<int>
{
public SumActivity(Variable<int> a, Variable<int> b)
{
A = new(a);
B = new(b);
}
public Input<int> A { get; set; }
public Input<int> B { get; set; }
protected override void Execute(ActivityExecutionContext context)
{
var input1 = A.Get(context);
var input2 = B.Get(context);
var result = input1 + input2;
// All three work.
Result.Set(context, result);
}
}
@@ -0,0 +1,29 @@
using Elsa.Extensions;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Memory;
namespace Elsa.Workflows.IntegrationTests.Scenarios.ActivityOutputs;
public class SumWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder workflow)
{
var a = new Variable<int>("A", 0);
var b = new Variable<int>("B", 0);
var sumActivity = new SumActivity(a, b);
workflow.Root = new Sequence
{
Variables = { a, b },
Activities =
{
new Inline(context => a.Set(context, 4)),
new Inline(context => b.Set(context, 6)),
sumActivity,
new WriteLine(context => $"The result of {a.Get(context)} and {b.Get(context)} is {sumActivity.GetResult<int>(context)}."),
new WriteLine(context => $"The last result is {context.GetLastResult<int>()}."),
}
};
}
}
@@ -0,0 +1,44 @@
using Elsa.Testing.Shared;
using Microsoft.Extensions.DependencyInjection;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.ActivityOutputs;
public class Tests
{
private readonly IWorkflowRunner _workflowRunner;
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly IServiceProvider _services;
public Tests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper).WithCapturingTextWriter(_capturingTextWriter).Build();
_workflowRunner = _services.GetRequiredService<IWorkflowRunner>();
}
[Fact(DisplayName = "Activity outputs can be accessed from other activities.")]
public async Task Test1()
{
await _services.PopulateRegistriesAsync();
await _workflowRunner.RunAsync<SumWorkflow>();
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(new[]
{
"The result of 4 and 6 is 10.", "The last result is 10."
}, lines);
}
[Fact(DisplayName = "The last activity output is returned.")]
public async Task Test2()
{
await _services.PopulateRegistriesAsync();
await _workflowRunner.RunAsync<LoopingWorkflow>();
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(new[]
{
"Current value: Item 1, Activity result: Item 1",
"Current value: Item 2, Activity result: Item 2",
"Current value: Item 3, Activity result: Item 3"
}, lines);
}
}
@@ -0,0 +1,50 @@
using Elsa.Extensions;
using Elsa.Testing.Shared;
using Elsa.Workflows.Options;
using Microsoft.Extensions.DependencyInjection;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.Blocking;
public class Tests
{
private readonly IWorkflowRunner _workflowRunner;
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly IWorkflowBuilderFactory _workflowBuilderFactory;
private readonly IServiceProvider _services;
public Tests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper).WithCapturingTextWriter(_capturingTextWriter).Build();
_workflowBuilderFactory = _services.GetRequiredService<IWorkflowBuilderFactory>();
_workflowRunner = _services.GetRequiredService<IWorkflowRunner>();
}
[Fact(DisplayName = "Subsequent activity does not get scheduled when previous activity created a bookmark")]
public async Task Test1()
{
await _services.PopulateRegistriesAsync();
await _workflowRunner.RunAsync<BlockingSequentialWorkflow>();
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(new[] { "Line 1" }, lines);
}
[Fact(DisplayName = "Subsequent activities are scheduled when resuming workflow using bookmark")]
public async Task Test2()
{
await _services.PopulateRegistriesAsync();
var workflow = await _workflowBuilderFactory.CreateBuilder().BuildWorkflowAsync<BlockingSequentialWorkflow>();
// Start workflow.
var result = await _workflowRunner.RunAsync(workflow);
var bookmark = result.WorkflowState.Bookmarks.FirstOrDefault(x => x.ActivityId == "Resume");
// Resume workflow.
var runOptions = new RunWorkflowOptions { BookmarkId = bookmark!.Id };
await _workflowRunner.RunAsync(workflow, result.WorkflowState, runOptions);
// Verify expected output.
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(new[] { "Line 1", "Line 2", "Line 3" }, lines);
}
}
@@ -0,0 +1,21 @@
using Elsa.Workflows.Activities;
using Elsa.Workflows.Runtime.Activities;
namespace Elsa.Workflows.IntegrationTests.Scenarios.Blocking;
class BlockingSequentialWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder workflow)
{
workflow.Root = new Sequence
{
Activities =
{
new WriteLine("Line 1"),
new Event("Resume"){ Id = "Resume"},
new WriteLine("Line 2"),
new WriteLine("Line 3")
}
};
}
}
@@ -0,0 +1,88 @@
using Elsa.Extensions;
using Elsa.Testing.Shared;
using Elsa.Workflows.IntegrationTests.Scenarios.BlockingAndBreaking.Workflows;
using Elsa.Workflows.Options;
using Microsoft.Extensions.DependencyInjection;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.BlockingAndBreaking;
public class Tests
{
private readonly IWorkflowRunner _workflowRunner;
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly IWorkflowBuilderFactory _workflowBuilderFactory;
private readonly IServiceProvider _services;
public Tests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper).WithCapturingTextWriter(_capturingTextWriter).Build();
_workflowBuilderFactory = _services.GetRequiredService<IWorkflowBuilderFactory>();
_workflowRunner = _services.GetRequiredService<IWorkflowRunner>();
}
[Fact(DisplayName = "Fork completes after all branches complete.")]
public async Task Test1()
{
await _services.PopulateRegistriesAsync();
var workflow = await _workflowBuilderFactory.CreateBuilder().BuildWorkflowAsync<WaitAllForkWorkflow>();
// Start workflow.
var result1 = await _workflowRunner.RunAsync(workflow);
// Resume the first branch.
var bookmark = result1.WorkflowState.Bookmarks.FirstOrDefault(x => x.ActivityId == "Branch 1");
var runOptions = new RunWorkflowOptions { BookmarkId = bookmark!.Id };
var result2 = await _workflowRunner.RunAsync(workflow, result1.WorkflowState, runOptions);
// Resume the second branch.
bookmark = result2.WorkflowState.Bookmarks.FirstOrDefault(x => x.ActivityId == "Branch 2");
runOptions = new RunWorkflowOptions { BookmarkId = bookmark!.Id };
var result3 = await _workflowRunner.RunAsync(workflow, result2.WorkflowState, runOptions);
// Verify expected output.
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(new[] { "Start", "Branch 1", "Branch 2", "Branch 1 - Resumed", "Branch 2 - Resumed", "End" }, lines);
}
[Fact(DisplayName = "Fork completes after any branch completes.")]
public async Task Test2()
{
await _services.PopulateRegistriesAsync();
var workflow = await _workflowBuilderFactory.CreateBuilder().BuildWorkflowAsync<WaitAnyForkWorkflow>();
// Start workflow.
var result1 = await _workflowRunner.RunAsync(workflow);
// Resume the first branch.
var bookmark = result1.WorkflowState.Bookmarks.FirstOrDefault(x => x.ActivityId == "Branch 1");
var runOptions = new RunWorkflowOptions { BookmarkId = bookmark!.Id };
var result2 = await _workflowRunner.RunAsync(workflow, result1.WorkflowState, runOptions);
// Verify expected output.
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(new[] { "Start", "Branch 1", "Branch 2", "Branch 1 - Resumed", "End" }, lines);
}
[Fact(DisplayName = "Break breaks out of While loop.")]
public async Task Test3()
{
await _services.PopulateRegistriesAsync();
var workflow = await _workflowBuilderFactory.CreateBuilder().BuildWorkflowAsync<BreakWhileFromForkWorkflow>();
// Start workflow.
var result1 = await _workflowRunner.RunAsync(workflow);
// Resume the first branch.
var bookmark = result1.WorkflowState.Bookmarks.FirstOrDefault(x => x.ActivityId == "Branch 1");
var runOptions = new RunWorkflowOptions { BookmarkId = bookmark!.Id };
var result2 = await _workflowRunner.RunAsync(workflow, result1.WorkflowState, runOptions);
// There should be no bookmarks left, since the while loop was broken out of.
Assert.Empty(result2.WorkflowState.Bookmarks);
// Verify expected output.
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(new[] { "Start", "Branch 1", "Branch 2", "Branch 1 - Resumed", "End" }, lines);
}
}
@@ -0,0 +1,61 @@
using Elsa.Workflows.Activities;
using Elsa.Workflows.Memory;
using Elsa.Workflows.Runtime.Activities;
namespace Elsa.Workflows.IntegrationTests.Scenarios.BlockingAndBreaking.Workflows;
public class BreakWhileFromForkWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder workflow)
{
var currentValue = new Variable<int?>("CurrentValue", 0);
workflow.WithVariable(currentValue);
workflow.Root = new Sequence
{
Activities =
{
new WriteLine("Start"),
new While(() => true)
{
Body = new Sequence
{
Activities =
{
new Fork
{
JoinMode = ForkJoinMode.WaitAll,
Branches =
{
new Sequence
{
Activities =
{
new WriteLine("Branch 1"),
new Event("Branch 1") { Id = "Branch 1" },
new WriteLine("Branch 1 - Resumed"),
// This should break the while loop, not matter how high up in the tree it is.
new Break()
}
},
new Sequence
{
Activities =
{
new WriteLine("Branch 2"),
new Event("Branch 2") { Id = "Branch 2" },
new WriteLine("Branch 2 - Resumed"),
}
}
}
}
}
}
},
new WriteLine("End")
}
};
}
}
@@ -0,0 +1,50 @@
using Elsa.Workflows.Activities;
using Elsa.Workflows.Memory;
using Elsa.Workflows.Runtime.Activities;
namespace Elsa.Workflows.IntegrationTests.Scenarios.BlockingAndBreaking.Workflows;
public class WaitAllForkWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder workflow)
{
var currentValue = new Variable<int?>("CurrentValue", 0);
workflow.WithVariable(currentValue);
workflow.Root =
new Sequence
{
Activities =
{
new WriteLine("Start"),
new Fork
{
JoinMode = ForkJoinMode.WaitAll,
Branches =
{
new Sequence
{
Activities =
{
new WriteLine("Branch 1"),
new Event("Branch 1") { Id = "Branch 1" },
new WriteLine("Branch 1 - Resumed"),
}
},
new Sequence
{
Activities =
{
new WriteLine("Branch 2"),
new Event("Branch 2") { Id = "Branch 2" },
new WriteLine("Branch 2 - Resumed"),
}
}
}
},
new WriteLine("End")
}
};
}
}
@@ -0,0 +1,50 @@
using Elsa.Workflows.Activities;
using Elsa.Workflows.Memory;
using Elsa.Workflows.Runtime.Activities;
namespace Elsa.Workflows.IntegrationTests.Scenarios.BlockingAndBreaking.Workflows;
public class WaitAnyForkWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder workflow)
{
var currentValue = new Variable<int?>("CurrentValue", 0);
workflow.WithVariable(currentValue);
workflow.Root =
new Sequence
{
Activities =
{
new WriteLine("Start"),
new Fork
{
JoinMode = ForkJoinMode.WaitAny,
Branches =
{
new Sequence
{
Activities =
{
new WriteLine("Branch 1"),
new Event("Branch 1") { Id = "Branch 1" },
new WriteLine("Branch 1 - Resumed"),
}
},
new Sequence
{
Activities =
{
new WriteLine("Branch 2"),
new Event("Branch 2") { Id = "Branch 2" },
new WriteLine("Branch 2 - Resumed"),
}
}
}
},
new WriteLine("End")
}
};
}
}
@@ -0,0 +1,33 @@
using Elsa.Expressions.Models;
using Elsa.Extensions;
using Elsa.Workflows.Models;
namespace Elsa.Workflows.IntegrationTests.Scenarios.CanExecute.Activities;
public class CustomActivity : CodeActivity
{
public CustomActivity(int magicNumber)
{
MagicNumber = new (magicNumber);
}
public CustomActivity(Func<ExpressionExecutionContext, int> magicNumber)
{
MagicNumber = new (magicNumber);
}
public Input<int> MagicNumber { get; set; }
protected override bool CanExecute(ActivityExecutionContext context)
{
var magicNumber = MagicNumber.Get(context);
return magicNumber == 42;
}
protected override void Execute(ActivityExecutionContext context)
{
var provider = context.GetService<IStandardOutStreamProvider>() ?? new StandardOutStreamProvider(Console.Out);
var textWriter = provider.GetTextWriter();
textWriter.WriteLine("Welcome to the world of Might and Magic!");
}
}
@@ -0,0 +1,43 @@
using Elsa.Testing.Shared;
using Elsa.Workflows.IntegrationTests.Scenarios.CanExecute.Activities;
using Elsa.Workflows.IntegrationTests.Scenarios.CanExecute.Workflows;
using Elsa.Workflows.Options;
using Microsoft.Extensions.DependencyInjection;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.CanExecute;
public class CanExecuteTests
{
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly IServiceProvider _services;
private readonly IWorkflowRunner _workflowRunner;
public CanExecuteTests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper)
.WithCapturingTextWriter(_capturingTextWriter)
.AddActivitiesFrom<CustomActivity>()
.Build();
_workflowRunner = _services.GetRequiredService<IWorkflowRunner>();
}
[Theory(DisplayName = "Activities are executed only when they report that they can execute.")]
[InlineData(12, "Magic number is 12")]
[InlineData(42, "Magic number is 42\nWelcome to the world of Might and Magic!\nDone")]
public async Task Test1(int magicNumber, string expectedLines)
{
await _services.PopulateRegistriesAsync();
var runOptions = new RunWorkflowOptions
{
Input = new Dictionary<string, object>
{
["MagicNumber"] = magicNumber
}
};
await _workflowRunner.RunAsync<MagicWorkflow>(runOptions);
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(expectedLines.Split('\n', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries), lines);
}
}
@@ -0,0 +1,24 @@
using Elsa.Extensions;
using Elsa.Workflows.Activities;
using Elsa.Workflows.IntegrationTests.Scenarios.CanExecute.Activities;
namespace Elsa.Workflows.IntegrationTests.Scenarios.CanExecute.Workflows;
public class MagicWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder builder)
{
var magicNumberVariable = builder.WithVariable<int>();
builder.Root = new Sequence
{
Activities =
{
new SetVariable<int>(magicNumberVariable, context => context.GetInput<int>("MagicNumber")),
new WriteLine(context => $"Magic number is {magicNumberVariable.Get(context)}"),
new CustomActivity(context => magicNumberVariable.Get(context)),
new WriteLine("Done")
}
};
}
}
@@ -0,0 +1,38 @@
using Elsa.Extensions;
using Elsa.Testing.Shared;
using Microsoft.Extensions.DependencyInjection;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.Composites;
public class Tests
{
private readonly IWorkflowRunner _workflowRunner;
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly IWorkflowBuilderFactory _workflowBuilderFactory;
private readonly IServiceProvider _services;
public Tests(ITestOutputHelper testOutputHelper)
{
_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()
{
await _services.PopulateRegistriesAsync();
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,72 @@
using Elsa.Extensions;
using Elsa.JavaScript.Activities;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Memory;
using Elsa.Workflows.Models;
namespace Elsa.Workflows.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; } = null!;
public Input<int> B { get; set; } = null!;
public Sum()
{
_runJavaScript = new()
{
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(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 = workflow.WithVariable<int>("Sum", 0);
workflow.Root = new Sequence
{
Activities =
{
new Sum
{
A = new(1),
B = new(2),
Result = new(sum)
},
new WriteLine(context => $"Sum: {sum.Get(context)}")
}
};
}
}
@@ -0,0 +1,36 @@
using Elsa.Testing.Shared;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.CompositesAndOutcomes;
public class ExplicitJoinWaitAnyTests
{
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly IServiceProvider _services;
public ExplicitJoinWaitAnyTests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper)
.WithCapturingTextWriter(_capturingTextWriter)
.WithWorkflowsFromDirectory("Scenarios", "CompositesAndOutcomes", "Workflows")
.Build();
}
[Fact(DisplayName = "Complete activity must not cascade.")]
public async Task Test1()
{
// Populate registries.
await _services.PopulateRegistriesAsync();
// Execute.
var workflowState = await _services.RunWorkflowUntilEndAsync("tester");
// Assert expected output.
var lines = _capturingTextWriter.Lines.ToList();
var expectedLinesArray = new[] { "Start", "End" };
Assert.Equal(expectedLinesArray, lines);
// Assert expected workflow status.
Assert.Equal(WorkflowStatus.Finished, workflowState.Status);
}
}
@@ -0,0 +1,71 @@
{
"id": "3457460b3fd74daa8f898564cf96fe48",
"definitionId": "99c1c6cf2fec47b3b4916a01425ec989",
"name": "Completor",
"createdAt": "2023-09-14T13:49:38.017111+00:00",
"version": 1,
"toolVersion": "3.0.0.0",
"variables": [],
"inputs": [],
"outputs": [],
"outcomes": [
"Success",
"Failure"
],
"customProperties": {},
"isReadonly": false,
"isLatest": true,
"isPublished": true,
"options": {
"usableAsActivity": true,
"autoUpdateConsumingWorkflows": true,
"activityCategory": "Testing"
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "Gn-5gEC2-UCmmzWTgvYCmw",
"metadata": {},
"customProperties": {
"source": "FlowchartJsonConverter.cs:46",
"notFoundConnections": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"activities": [
{
"outcomes": {
"typeName": "Object",
"expression": {
"type": "Literal",
"value": "Success"
},
"memoryReference": {
"id": "tyDvLNGiYkCbUabhgzcSdw:input-0"
}
},
"id": "tyDvLNGiYkCbUabhgzcSdw",
"name": "Complete1",
"type": "Elsa.Complete",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -186.5,
"y": -263
},
"size": {
"width": 136.8125,
"height": 50
}
}
}
}
],
"connections": []
}
}
@@ -0,0 +1,62 @@
{
"id": "9b6b4d4a6a8741c58ccbe3911eed7821",
"definitionId": "bc7f148b2a5b4f55811537a0d762e137",
"name": "Consumer",
"createdAt": "2023-09-14T13:50:13.31251+00:00",
"version": 1,
"toolVersion": "3.0.0.0",
"variables": [],
"inputs": [],
"outputs": [],
"outcomes": [],
"customProperties": {},
"isReadonly": false,
"isLatest": true,
"isPublished": true,
"options": {
"usableAsActivity": true,
"autoUpdateConsumingWorkflows": true,
"activityCategory": "Testing"
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "v-ii0Vp0yUCPWReLNUiosg",
"metadata": {},
"customProperties": {
"source": "FlowchartJsonConverter.cs:46",
"notFoundConnections": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"activities": [
{
"workflowDefinitionId": "99c1c6cf2fec47b3b4916a01425ec989",
"workflowDefinitionVersionId": "3457460b3fd74daa8f898564cf96fe48",
"latestAvailablePublishedVersion": 1,
"latestAvailablePublishedVersionId": "3457460b3fd74daa8f898564cf96fe48",
"id": "ctusr1Uv40uFqIws9Ymt9A",
"name": "Completor1",
"type": "Completor",
"version": 2,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 20,
"y": -260
},
"size": {
"width": 106.859375,
"height": 116.015625
}
}
}
}
],
"connections": []
}
}
@@ -0,0 +1,145 @@
{
"id": "74144d614208497380a7bae783b78626",
"definitionId": "tester",
"name": "Tester",
"createdAt": "2023-09-14T13:50:38.720025+00:00",
"version": 1,
"toolVersion": "3.0.0.0",
"variables": [],
"inputs": [],
"outputs": [],
"outcomes": [],
"customProperties": {},
"isReadonly": false,
"isLatest": true,
"isPublished": true,
"options": {
"autoUpdateConsumingWorkflows": false
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "k0HQeDE_gk-OxcsjGj3tbQ",
"metadata": {},
"customProperties": {
"source": "FlowchartJsonConverter.cs:46",
"notFoundConnections": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"activities": [
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "Start"
},
"memoryReference": {
"id": "35MeNlWlAUKXd5JFDJtJ3w:input-0"
}
},
"id": "35MeNlWlAUKXd5JFDJtJ3w",
"name": "WriteLine1",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -198,
"y": -246.9921875
},
"size": {
"width": 139.296875,
"height": 50
}
}
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "End"
},
"memoryReference": {
"id": "CvdSrKs5DESezhkLjb0YIw:input-0"
}
},
"id": "CvdSrKs5DESezhkLjb0YIw",
"name": "WriteLine2",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 253,
"y": -246.9921875
},
"size": {
"width": 139.296875,
"height": 50
}
}
}
},
{
"workflowDefinitionId": "bc7f148b2a5b4f55811537a0d762e137",
"workflowDefinitionVersionId": "9b6b4d4a6a8741c58ccbe3911eed7821",
"latestAvailablePublishedVersion": 1,
"latestAvailablePublishedVersionId": "9b6b4d4a6a8741c58ccbe3911eed7821",
"id": "QfkYnRZDxEO0rtBTIbTXzg",
"name": "Consumer1",
"type": "Consumer",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 20,
"y": -280
},
"size": {
"width": 105.5625,
"height": 116.015625
}
}
}
}
],
"connections": [
{
"source": {
"activity": "35MeNlWlAUKXd5JFDJtJ3w",
"port": "Done"
},
"target": {
"activity": "QfkYnRZDxEO0rtBTIbTXzg",
"port": "In"
}
},
{
"source": {
"activity": "QfkYnRZDxEO0rtBTIbTXzg",
"port": "Done"
},
"target": {
"activity": "CvdSrKs5DESezhkLjb0YIw",
"port": "In"
}
}
]
}
}
@@ -0,0 +1,38 @@
using Elsa.Extensions;
using Elsa.Testing.Shared;
using Microsoft.Extensions.DependencyInjection;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.CompositesPassingData;
public class Tests
{
private readonly IWorkflowRunner _workflowRunner;
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly IWorkflowBuilderFactory _workflowBuilderFactory;
private readonly IServiceProvider _services;
public Tests(ITestOutputHelper testOutputHelper)
{
_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()
{
await _services.PopulateRegistriesAsync();
var workflow = await _workflowBuilderFactory.CreateBuilder().BuildWorkflowAsync<AddTextMainWorkflow>();
// Start workflow.
await _workflowRunner.RunAsync(workflow);
// Verify expected output.
var line = _capturingTextWriter.Lines.ToList().Last();
Assert.Equal("hi there obi wan", line);
}
}
@@ -0,0 +1,61 @@
using Elsa.Extensions;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Management.Activities.SetOutput;
using Elsa.Workflows.Memory;
using Elsa.Workflows.Models;
namespace Elsa.Workflows.IntegrationTests.Scenarios.CompositesPassingData;
/// <summary>
/// A composite activity that adds text to a string
/// </summary>
public class AddTextSubWorkflow : Composite
{
public Input<string> A { get; set; } = default!;
public Output<string> B { get; set; } = default!;
public AddTextSubWorkflow()
{
var setOutput = new SetOutput()
{
OutputName = new Input<string>("B"),
OutputValue = new Input<object?>(context => "hi there " + A.Get(context))
};
Root = new Sequence
{
Activities =
{
setOutput
}
};
}
}
/// <summary>
/// A workflow that uses the <see cref="AddTextSubWorkflow"/> composite activity.
/// </summary>
public class AddTextMainWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder workflow)
{
var outVariable = new Variable<string>("out", "test");
var subWorkflow = new AddTextSubWorkflow()
{
A = new("obi wan"),
B = new (outVariable)
};
workflow.Variables.Add(outVariable);
workflow.Root = new Sequence
{
Activities =
{
subWorkflow,
new WriteLine(context => outVariable.Get(context))
}
};
}
}
@@ -0,0 +1,33 @@
using Elsa.Testing.Shared;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.DependencyWorkflows;
public class Tests
{
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly IServiceProvider _services;
public Tests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper)
.WithCapturingTextWriter(_capturingTextWriter)
.WithWorkflowsFromDirectory("Scenarios", "DependencyWorkflows", "Workflows")
.Build();
}
[Fact(DisplayName = "Workflows provided from JSON files that depend on other workflows are executed correctly.")]
public async Task Test1()
{
// Populate registries.
await _services.PopulateRegistriesAsync();
// Run the "matter" workflow.
await _services.RunWorkflowUntilEndAsync("matter-workflow");
// Assert.
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(new[] { "Atom", "Atom", "Atom", "Atom", "Atom", "Atom", "Atom", "Atom", "Atom" }, lines);
}
}
@@ -0,0 +1,61 @@
{
"id": "82b53ccf2a4e4ced966b85fb3cc13eed",
"definitionId": "40a40a0cdf5448acbc899391b2c50458",
"name": "AtomActivity",
"createdAt": "2023-06-01T14:00:29.374132+00:00",
"version": 1,
"variables": [],
"inputs": [],
"outputs": [],
"outcomes": [],
"customProperties": {},
"usableAsActivity": true,
"isLatest": true,
"isPublished": true,
"options": {
"autoUpdateConsumingWorkflows": true
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "Flowchart1",
"metadata": {},
"applicationProperties": {
"NotFoundConnectionsKey": [],
"CanStartWorkflow": false,
"RunAsynchronously": false
},
"start": "Atom",
"activities": [
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "Atom"
},
"memoryReference": {
"id": "65ee0198-2051-491d-9035-6d05e73fbd08"
}
},
"id": "Atom",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"CanStartWorkflow": false,
"RunAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 2394,
"y": 2472
}
},
"displayText": "Atom"
}
}
],
"connections": []
}
}
@@ -0,0 +1,105 @@
{
"id": "matter-workflow-v1",
"definitionId": "matter-workflow",
"name": "Matter Workflow",
"createdAt": "2023-06-01T14:06:25.895316+00:00",
"version": 1,
"variables": [],
"inputs": [],
"outputs": [],
"outcomes": [],
"customProperties": {},
"isLatest": true,
"isPublished": true,
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "Flowchart1",
"metadata": {},
"applicationProperties": {
"NotFoundConnectionsKey": [],
"CanStartWorkflow": false,
"RunAsynchronously": false
},
"start": "MoleculeActivity2",
"activities": [
{
"workflowDefinitionId": "86e355d944764f15872f8cfdcc1e9cec",
"workflowDefinitionVersionId": "fec9de7279a440f693a5901507140a77",
"latestAvailablePublishedVersion": 1,
"latestAvailablePublishedVersionId": "fec9de7279a440f693a5901507140a77",
"id": "MoleculeActivity1",
"type": "MoleculeActivity",
"version": 1,
"customProperties": {
"CanStartWorkflow": false,
"RunAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 2347,
"y": 2407
}
}
}
},
{
"workflowDefinitionId": "86e355d944764f15872f8cfdcc1e9cec",
"workflowDefinitionVersionId": "fec9de7279a440f693a5901507140a77",
"latestAvailablePublishedVersion": 1,
"latestAvailablePublishedVersionId": "fec9de7279a440f693a5901507140a77",
"id": "MoleculeActivity3",
"type": "MoleculeActivity",
"version": 1,
"customProperties": {
"CanStartWorkflow": false,
"RunAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 2560,
"y": 2560
}
}
}
},
{
"workflowDefinitionId": "86e355d944764f15872f8cfdcc1e9cec",
"workflowDefinitionVersionId": "fec9de7279a440f693a5901507140a77",
"latestAvailablePublishedVersion": 1,
"latestAvailablePublishedVersionId": "fec9de7279a440f693a5901507140a77",
"id": "MoleculeActivity2",
"type": "MoleculeActivity",
"version": 1,
"customProperties": {
"CanStartWorkflow": false,
"RunAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 2140,
"y": 2560
}
}
}
}
],
"connections": [
{
"source": "MoleculeActivity2",
"target": "MoleculeActivity1",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "MoleculeActivity1",
"target": "MoleculeActivity3",
"sourcePort": "Done",
"targetPort": "In"
}
]
}
}
@@ -0,0 +1,109 @@
{
"id": "fec9de7279a440f693a5901507140a77",
"definitionId": "86e355d944764f15872f8cfdcc1e9cec",
"name": "MoleculeActivity",
"createdAt": "2023-06-01T14:05:32.409643+00:00",
"version": 1,
"variables": [],
"inputs": [],
"outputs": [],
"outcomes": [],
"customProperties": {},
"isLatest": true,
"isPublished": true,
"options": {
"usableAsActivity": true,
"autoUpdateConsumingWorkflows": true
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "Flowchart1",
"metadata": {},
"applicationProperties": {
"NotFoundConnectionsKey": [],
"CanStartWorkflow": false,
"RunAsynchronously": false
},
"start": "AtomActivity1",
"activities": [
{
"workflowDefinitionId": "40a40a0cdf5448acbc899391b2c50458",
"workflowDefinitionVersionId": "82b53ccf2a4e4ced966b85fb3cc13eed",
"latestAvailablePublishedVersion": 1,
"latestAvailablePublishedVersionId": "82b53ccf2a4e4ced966b85fb3cc13eed",
"id": "AtomActivity1",
"type": "AtomActivity",
"version": 1,
"customProperties": {
"CanStartWorkflow": false,
"RunAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 2228,
"y": 2418
}
}
}
},
{
"workflowDefinitionId": "40a40a0cdf5448acbc899391b2c50458",
"workflowDefinitionVersionId": "82b53ccf2a4e4ced966b85fb3cc13eed",
"latestAvailablePublishedVersion": 1,
"latestAvailablePublishedVersionId": "82b53ccf2a4e4ced966b85fb3cc13eed",
"id": "AtomActivity2",
"type": "AtomActivity",
"version": 1,
"customProperties": {
"CanStartWorkflow": false,
"RunAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 2458,
"y": 2487
}
}
}
},
{
"workflowDefinitionId": "40a40a0cdf5448acbc899391b2c50458",
"workflowDefinitionVersionId": "82b53ccf2a4e4ced966b85fb3cc13eed",
"latestAvailablePublishedVersion": 1,
"latestAvailablePublishedVersionId": "82b53ccf2a4e4ced966b85fb3cc13eed",
"id": "AtomActivity3",
"type": "AtomActivity",
"version": 1,
"customProperties": {
"CanStartWorkflow": false,
"RunAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 2660,
"y": 2560
}
}
}
}
],
"connections": [
{
"source": "AtomActivity1",
"target": "AtomActivity2",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "AtomActivity2",
"target": "AtomActivity3",
"sourcePort": "Done",
"targetPort": "In"
}
]
}
}
@@ -0,0 +1,71 @@
using Elsa.Common.Models;
using Elsa.Extensions;
using Elsa.Testing.Shared;
using Elsa.Workflows.Management;
using Elsa.Workflows.Management.Activities.WorkflowDefinitionActivity;
using Elsa.Workflows.Management.Entities;
using Microsoft.Extensions.DependencyInjection;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.DependencyWorkflowsPublishing;
/// <summary>
/// Contains tests for the "DependencyWorkflowsPublishing" scenario.
/// </summary>
public class Tests
{
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly IServiceProvider _services;
private readonly IWorkflowDefinitionPublisher _workflowDefinitionPublisher;
private readonly IActivitySerializer _activitySerializer;
private readonly IActivityVisitor _activityVisitor;
/// <summary>
/// Initializes a new instance of the <see cref="Tests"/> class.
/// </summary>
public Tests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper)
.WithCapturingTextWriter(_capturingTextWriter)
.WithWorkflowsFromDirectory("Scenarios", "DependencyWorkflowsPublishing", "Workflows")
.Build();
_workflowDefinitionPublisher = _services.GetRequiredService<IWorkflowDefinitionPublisher>();
_activitySerializer = _services.GetRequiredService<IActivitySerializer>();
_activityVisitor = _services.GetRequiredService<IActivityVisitor>();
}
/// <summary>
/// When a dependency workflow is published, all consuming workflows are updated to point to the new version of the dependency.
/// </summary>
[Fact(DisplayName = "When a dependency workflow is published, all consuming workflows are updated to point to the new version of the dependency.")]
public async Task Test1()
{
await _services.PopulateRegistriesAsync();
var childDefinitionV1 = await _services.GetWorkflowDefinitionAsync("child", VersionOptions.Latest);
var parentDefinition = await _services.GetWorkflowDefinitionAsync("parent", VersionOptions.Latest);
var childActivityV1 = await GetChildActivityAsync(parentDefinition);
// Assert initial state.
Assert.Equal(1, childDefinitionV1.Version);
Assert.False(parentDefinition.IsPublished);
Assert.Equal(1, childActivityV1.Version);
// Create a new draft for the child workflow and publish it.
var childDefinitionV2 = (await _workflowDefinitionPublisher.GetDraftAsync(childDefinitionV1.DefinitionId, VersionOptions.Published))!;
await _workflowDefinitionPublisher.PublishAsync(childDefinitionV2);
// Assert that the parent workflow now points to the new version of the child workflow.
parentDefinition = await _services.GetWorkflowDefinitionAsync("parent", VersionOptions.Latest);
var childActivityV2 = await GetChildActivityAsync(parentDefinition);
Assert.Equal(2, childActivityV2.Version);
}
private async Task<WorkflowDefinitionActivity> GetChildActivityAsync(WorkflowDefinition parent)
{
var root = _activitySerializer.Deserialize(parent.StringData!);
var graph = await _activityVisitor.VisitAsync(root);
var flattenedList = graph.Flatten().ToList();
return (WorkflowDefinitionActivity)flattenedList.Single(x => x.Activity is WorkflowDefinitionActivity { WorkflowDefinitionId: "child" }).Activity;
}
}
@@ -0,0 +1,37 @@
{
"id": "child-v1",
"definitionId": "child",
"name": "Child",
"createdAt": "2024-02-07T14:57:47.115341+00:00",
"version": 1,
"toolVersion": "3.0.0.0",
"variables": [],
"inputs": [],
"outputs": [],
"outcomes": [],
"customProperties": {
"Elsa:WorkflowContextProviderTypes": []
},
"isReadonly": false,
"isLatest": true,
"isPublished": true,
"options": {
"usableAsActivity": true,
"autoUpdateConsumingWorkflows": true
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "c22918340b6cb7cd",
"nodeId": "Workflow1:c22918340b6cb7cd",
"metadata": {},
"customProperties": {
"source": "FlowchartJsonConverter.cs:45",
"notFoundConnections": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"activities": [],
"connections": []
}
}
@@ -0,0 +1,64 @@
{
"id": "ffd312ccf7a2af4f",
"definitionId": "parent",
"name": "Parent",
"createdAt": "2024-02-07T14:58:12.954939+00:00",
"version": 1,
"toolVersion": "3.0.0.0",
"variables": [],
"inputs": [],
"outputs": [],
"outcomes": [],
"customProperties": {
"Elsa:WorkflowContextProviderTypes": []
},
"isReadonly": false,
"isLatest": true,
"isPublished": false,
"options": {
"autoUpdateConsumingWorkflows": false
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "3535b9598a0962f0",
"nodeId": "Workflow1:3535b9598a0962f0",
"metadata": {},
"customProperties": {
"source": "FlowchartJsonConverter.cs:45",
"notFoundConnections": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"activities": [
{
"workflowDefinitionId": "child",
"workflowDefinitionVersionId": "child-v1",
"latestAvailablePublishedVersion": 1,
"latestAvailablePublishedVersionId": "child-v1",
"id": "35525d3b78b8e518",
"nodeId": "Workflow1:3535b9598a0962f0:35525d3b78b8e518",
"name": "Child1",
"type": "Child",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -95.17782592773438,
"y": -137.3333282470703
},
"size": {
"width": 67.78125,
"height": 50
}
}
}
}
],
"connections": []
}
}
@@ -0,0 +1,42 @@
using Elsa.Testing.Shared;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.ExplicitJoins;
public class ExplicitJoinWaitAnyTests
{
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly IServiceProvider _services;
public ExplicitJoinWaitAnyTests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper)
.WithCapturingTextWriter(_capturingTextWriter)
.Build();
}
[Theory(DisplayName = "Workflows with explicit joins complete the workflow.")]
[InlineData("join-any-1.json", "Start; End")]
[InlineData("join-all-1.json", "Start; Line 1; Line 2; End")]
[InlineData("join-all-2.json", "Start; Line 1; Line 2; End")]
public async Task Test1(string filename, string expectedLines)
{
// Populate registries.
await _services.PopulateRegistriesAsync();
// Import workflow.
var fileName = $"Scenarios/ExplicitJoins/Workflows/{filename}";
var workflowDefinition = await _services.ImportWorkflowDefinitionAsync(fileName);
// Execute.
var workflowState = await _services.RunWorkflowUntilEndAsync(workflowDefinition.DefinitionId);
// Assert expected output.
var lines = _capturingTextWriter.Lines.ToList();
var expectedLinesArray = expectedLines.Split(";", StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries).ToList();
Assert.Equal(expectedLinesArray, lines);
// Assert expected workflow status.
Assert.Equal(WorkflowStatus.Finished, workflowState.Status);
}
}
@@ -0,0 +1,248 @@
{
"id": "9948e541b0e540c384c6eb9fdcf1d544",
"definitionId": "296428cc22bd4f309e858f4b461dbb3d",
"name": "Join 1",
"createdAt": "2023-09-12T18:12:54.370149+00:00",
"version": 2,
"toolVersion": "3.0.0.0",
"variables": [],
"inputs": [],
"outputs": [],
"outcomes": [],
"customProperties": {},
"isReadonly": false,
"isLatest": true,
"isPublished": true,
"options": {
"autoUpdateConsumingWorkflows": false
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "sL581qWiIEOpRncv5Ez33A",
"metadata": {},
"customProperties": {
"source": "FlowchartJsonConverter.cs:46",
"notFoundConnections": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"activities": [
{
"mode": {
"typeName": "Elsa.Workflows.Core.Activities.Flowchart.Models.FlowJoinMode, Elsa.Workflows.Core",
"expression": {
"type": "Literal",
"value": "WaitAll"
},
"memoryReference": {
"id": "aA4pfJOzyEqmLOY3U3vCoQ:input-0"
}
},
"id": "aA4pfJOzyEqmLOY3U3vCoQ",
"name": "FlowJoin1",
"type": "Elsa.FlowJoin",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 198,
"y": -266
},
"size": {
"width": 136.859375,
"height": 50
}
}
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "Start"
},
"memoryReference": {
"id": "FRXh0PlHekejZiWANAplUg:input-0"
}
},
"id": "FRXh0PlHekejZiWANAplUg",
"name": "WriteLine1",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -287,
"y": -266
},
"size": {
"width": 102.21875,
"height": 50
}
},
"displayText": "Start"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "Line 1"
},
"memoryReference": {
"id": "GaVrCWqBDkS6YrvydxKvFA:input-0"
}
},
"id": "GaVrCWqBDkS6YrvydxKvFA",
"name": "WriteLine2",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -40,
"y": -316
},
"size": {
"width": 110.65625,
"height": 50
}
},
"displayText": "Line 1"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "Line 2"
},
"memoryReference": {
"id": "9Z7bt98j00uRMt9TS2FD0g:input-0"
}
},
"id": "9Z7bt98j00uRMt9TS2FD0g",
"name": "WriteLine3",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -40,
"y": -207
},
"size": {
"width": 110.65625,
"height": 50
}
},
"displayText": "Line 2"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "End"
},
"memoryReference": {
"id": "MplDrS_bUE-8td-XBUvWmA:input-0"
}
},
"id": "MplDrS_bUE-8td-XBUvWmA",
"name": "WriteLine4",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 430,
"y": -266
},
"size": {
"width": 139.296875,
"height": 50
}
}
}
}
],
"connections": [
{
"source": {
"activity": "FRXh0PlHekejZiWANAplUg",
"port": "Done"
},
"target": {
"activity": "GaVrCWqBDkS6YrvydxKvFA",
"port": "In"
}
},
{
"source": {
"activity": "FRXh0PlHekejZiWANAplUg",
"port": "Done"
},
"target": {
"activity": "9Z7bt98j00uRMt9TS2FD0g",
"port": "In"
}
},
{
"source": {
"activity": "9Z7bt98j00uRMt9TS2FD0g",
"port": "Done"
},
"target": {
"activity": "aA4pfJOzyEqmLOY3U3vCoQ",
"port": "In"
}
},
{
"source": {
"activity": "GaVrCWqBDkS6YrvydxKvFA",
"port": "Done"
},
"target": {
"activity": "aA4pfJOzyEqmLOY3U3vCoQ",
"port": "In"
}
},
{
"source": {
"activity": "aA4pfJOzyEqmLOY3U3vCoQ",
"port": "Done"
},
"target": {
"activity": "MplDrS_bUE-8td-XBUvWmA",
"port": "In"
}
}
]
}
}
@@ -0,0 +1,287 @@
{
"id": "14984c048db34cceaf5e15ece80f9703",
"definitionId": "64f8f2c852f04dc28f60707034d7a906",
"name": "Join 2",
"createdAt": "2023-09-12T18:12:43.392272+00:00",
"version": 1,
"toolVersion": "3.0.0.0",
"variables": [],
"inputs": [],
"outputs": [],
"outcomes": [],
"customProperties": {},
"isReadonly": false,
"isLatest": true,
"isPublished": true,
"options": {
"autoUpdateConsumingWorkflows": false
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "B2jpPDriPEe-zSOhVuAGeQ",
"metadata": {},
"customProperties": {
"source": "FlowchartJsonConverter.cs:46",
"notFoundConnections": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"activities": [
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "Start"
},
"memoryReference": {
"id": "2yPLgUudQEGPaschdLdkGg:input-0"
}
},
"id": "2yPLgUudQEGPaschdLdkGg",
"name": "WriteLine1",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -358.5,
"y": -229
},
"size": {
"width": 139.296875,
"height": 50
}
},
"displayText": "Start"
}
},
{
"body": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "zaAIlUtQDEaPqeITeRJ4_w",
"metadata": {},
"customProperties": {
"source": "FlowchartJsonConverter.cs:46",
"notFoundConnections": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"activities": [
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "Line 2"
},
"memoryReference": {
"id": "g3jVTdvU3EK7V5JqRqfqjQ:input-0"
}
},
"id": "g3jVTdvU3EK7V5JqRqfqjQ",
"name": "WriteLine1",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -279.5,
"y": -294
},
"size": {
"width": 139.296875,
"height": 50
}
},
"displayText": "Line 2"
}
}
],
"connections": []
},
"id": "eHAEEQ-Iu0GwM3mRxZin0Q",
"name": "FlowNode1",
"type": "Elsa.FlowNode",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -120,
"y": -179
},
"size": {
"width": 211.15625,
"height": 120
}
},
"displayText": "Line 2"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "Line 1"
},
"memoryReference": {
"id": "7RQ2sbVHo0SxsyK0dvTKEA:input-0"
}
},
"id": "7RQ2sbVHo0SxsyK0dvTKEA",
"name": "WriteLine2",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -120,
"y": -279
},
"size": {
"width": 139.296875,
"height": 50
}
},
"displayText": "Line 1"
}
},
{
"mode": {
"typeName": "Elsa.Workflows.Core.Activities.Flowchart.Models.FlowJoinMode, Elsa.Workflows.Core",
"expression": {
"type": "Literal",
"value": "WaitAll"
},
"memoryReference": {
"id": "dVUuwMm5XUiYpiYoGo5JKA:input-0"
}
},
"id": "dVUuwMm5XUiYpiYoGo5JKA",
"name": "FlowJoin1",
"type": "Elsa.FlowJoin",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 180.5,
"y": -229
},
"size": {
"width": 136.859375,
"height": 50
}
}
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "End"
},
"memoryReference": {
"id": "NpZ_yT_irUuE9ASEfYLxbw:input-0"
}
},
"id": "NpZ_yT_irUuE9ASEfYLxbw",
"name": "WriteLine3",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 400,
"y": -229
},
"size": {
"width": 139.296875,
"height": 50
}
},
"displayText": "End"
}
}
],
"connections": [
{
"source": {
"activity": "2yPLgUudQEGPaschdLdkGg",
"port": "Done"
},
"target": {
"activity": "7RQ2sbVHo0SxsyK0dvTKEA",
"port": "In"
}
},
{
"source": {
"activity": "2yPLgUudQEGPaschdLdkGg",
"port": "Done"
},
"target": {
"activity": "eHAEEQ-Iu0GwM3mRxZin0Q",
"port": "In"
}
},
{
"source": {
"activity": "7RQ2sbVHo0SxsyK0dvTKEA",
"port": "Done"
},
"target": {
"activity": "dVUuwMm5XUiYpiYoGo5JKA",
"port": "In"
}
},
{
"source": {
"activity": "eHAEEQ-Iu0GwM3mRxZin0Q",
"port": "Done"
},
"target": {
"activity": "dVUuwMm5XUiYpiYoGo5JKA",
"port": "In"
}
},
{
"source": {
"activity": "dVUuwMm5XUiYpiYoGo5JKA",
"port": "Done"
},
"target": {
"activity": "NpZ_yT_irUuE9ASEfYLxbw",
"port": "In"
}
}
]
}
}
@@ -0,0 +1,245 @@
{
"id": "2484d1b14e2348f7a916ecef042536e6",
"definitionId": "7204b870946b4968aa786a2c91431242",
"name": "Flow Join Any",
"createdAt": "2023-09-08T19:07:08.435872+00:00",
"version": 1,
"toolVersion": "3.0.0.0",
"variables": [],
"inputs": [],
"outputs": [],
"outcomes": [],
"customProperties": {},
"isReadonly": false,
"isLatest": true,
"isPublished": false,
"options": {
"autoUpdateConsumingWorkflows": false
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "F44h770hvkSaOWI_jjbM_A",
"metadata": {},
"customProperties": {
"source": "FlowchartJsonConverter.cs:45",
"NotFoundConnectionsKey": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"activities": [
{
"mode": {
"typeName": "Elsa.Workflows.Core.Activities.Flowchart.Models.FlowJoinMode, Elsa.Workflows.Core",
"expression": {
"type": "Literal",
"value": "WaitAny"
},
"memoryReference": {
"id": "ImdIbHXtHkiLlrExFlW51A:input-0"
}
},
"id": "ImdIbHXtHkiLlrExFlW51A",
"name": "FlowJoin1",
"type": "Elsa.FlowJoin",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -180,
"y": -320
},
"size": {
"width": 136.859375,
"height": 50
}
}
}
},
{
"mode": {
"typeName": "Elsa.Workflows.Core.Activities.Flowchart.Models.FlowJoinMode, Elsa.Workflows.Core",
"expression": {
"type": "Literal",
"value": "WaitAny"
},
"memoryReference": {
"id": "cxnS1whoCESvwwPyBnno_Q:input-0"
}
},
"id": "cxnS1whoCESvwwPyBnno_Q",
"name": "FlowJoin2",
"type": "Elsa.FlowJoin",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -180,
"y": -80
},
"size": {
"width": 136.859375,
"height": 50
}
}
}
},
{
"mode": {
"typeName": "Elsa.Workflows.Core.Activities.Flowchart.Models.FlowJoinMode, Elsa.Workflows.Core",
"expression": {
"type": "Literal",
"value": "WaitAny"
},
"memoryReference": {
"id": "H0apwXYdoESn2TJ5T_3xAg:input-0"
}
},
"id": "H0apwXYdoESn2TJ5T_3xAg",
"name": "FlowJoin3",
"type": "Elsa.FlowJoin",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 40,
"y": -194
},
"size": {
"width": 136.859375,
"height": 50
}
}
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "Start"
},
"memoryReference": {
"id": "Kn9d-EVn2EiaYJqHd8VcmQ:input-0"
}
},
"id": "Kn9d-EVn2EiaYJqHd8VcmQ",
"name": "WriteLine1",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -393.5,
"y": -194
},
"size": {
"width": 139.296875,
"height": 50
}
}
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "End"
},
"memoryReference": {
"id": "haHoM3A5EU6aYu_8dCYaYg:input-0"
}
},
"id": "haHoM3A5EU6aYu_8dCYaYg",
"name": "WriteLine2",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 310.5,
"y": -194
},
"size": {
"width": 139.296875,
"height": 50
}
}
}
}
],
"connections": [
{
"source": {
"activity": "Kn9d-EVn2EiaYJqHd8VcmQ",
"port": "Done"
},
"target": {
"activity": "ImdIbHXtHkiLlrExFlW51A",
"port": "In"
}
},
{
"source": {
"activity": "Kn9d-EVn2EiaYJqHd8VcmQ",
"port": "Done"
},
"target": {
"activity": "cxnS1whoCESvwwPyBnno_Q",
"port": "In"
}
},
{
"source": {
"activity": "ImdIbHXtHkiLlrExFlW51A",
"port": "Done"
},
"target": {
"activity": "H0apwXYdoESn2TJ5T_3xAg",
"port": "In"
}
},
{
"source": {
"activity": "cxnS1whoCESvwwPyBnno_Q",
"port": "Done"
},
"target": {
"activity": "H0apwXYdoESn2TJ5T_3xAg",
"port": "In"
}
},
{
"source": {
"activity": "H0apwXYdoESn2TJ5T_3xAg",
"port": "Done"
},
"target": {
"activity": "haHoM3A5EU6aYu_8dCYaYg",
"port": "In"
}
}
]
}
}
@@ -0,0 +1,41 @@
using Elsa.Testing.Shared;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.FlowchartCompletion;
/// <summary>
/// Tests for the flowchart completion feature using various workflow setups.
/// </summary>
public class Tests
{
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly IServiceProvider _services;
public Tests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper).WithCapturingTextWriter(_capturingTextWriter).Build();
}
[Theory(DisplayName = "Workflows should complete successfully.")]
[InlineData("workflow1.json")]
[InlineData("workflow2.json")]
[InlineData("workflow3.json")]
[InlineData("workflow4.json")]
[InlineData("workflow5.json")]
[InlineData("workflow6.json")]
public async Task Test1(string workflowFileName)
{
// Populate registries.
await _services.PopulateRegistriesAsync();
// Import workflow.
var fileName = $"Scenarios/FlowchartCompletion/Workflows/{workflowFileName}";
var workflowDefinition = await _services.ImportWorkflowDefinitionAsync(fileName);
// Execute.
var workflowState = await _services.RunWorkflowUntilEndAsync(workflowDefinition.DefinitionId);
// Assert that the workflow has completed.
Assert.Equal(WorkflowStatus.Finished, workflowState.Status);
}
}
@@ -0,0 +1,127 @@
{
"id": "f7f7563b32de444797363df61e5109d3",
"definitionId": "d91eff09eaad43efb9d58332f1f22c82",
"name": "Flows",
"createdAt": "2023-04-18T13:32:26.294066+00:00",
"version": 1,
"variables": [],
"inputs": [],
"outputs": [],
"outcomes": [],
"metadata": {},
"isLatest": true,
"isPublished": false,
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "Flowchart1",
"metadata": {},
"applicationProperties": {
"NotFoundConnectionsKey": []
},
"start": "WriteLine1",
"activities": [
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine1"
},
"memoryReference": {
"id": "WriteLine1:input-1"
}
},
"id": "WriteLine1",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2020,
"y": 2320
}
},
"displayText": "WriteLine1"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine2"
},
"memoryReference": {
"id": "WriteLine2:input-1"
}
},
"id": "WriteLine2",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2260,
"y": 2260
}
},
"displayText": "WriteLine2"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine3"
},
"memoryReference": {
"id": "WriteLine3:input-1"
}
},
"id": "WriteLine3",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2260,
"y": 2380
}
},
"displayText": "WriteLine3"
}
}
],
"connections": [
{
"source": "WriteLine1",
"target": "WriteLine2",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine1",
"target": "WriteLine3",
"sourcePort": "Done",
"targetPort": "In"
}
]
}
}
@@ -0,0 +1,361 @@
{
"id": "dc6576d848aa4f46812356467575705f",
"definitionId": "991a4f39f7074a9988465230cfdb8d81",
"name": "Braided flow",
"createdAt": "2023-04-18T13:45:03.454228+00:00",
"version": 1,
"variables": [],
"inputs": [],
"outputs": [],
"outcomes": [],
"metadata": {},
"isLatest": true,
"isPublished": false,
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "Flowchart1",
"metadata": {},
"applicationProperties": {
"NotFoundConnectionsKey": []
},
"start": "WriteLine1",
"activities": [
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine7"
},
"memoryReference": {
"id": "WriteLine7:input-1"
}
},
"id": "WriteLine7",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2340,
"y": 2220
}
},
"displayText": "WriteLine7"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine9"
},
"memoryReference": {
"id": "WriteLine9:input-1"
}
},
"id": "WriteLine9",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2560,
"y": 2320
}
},
"displayText": "WriteLine9"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine1"
},
"memoryReference": {
"id": "WriteLine1:input-1"
}
},
"id": "WriteLine1",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 1600,
"y": 2320
}
},
"displayText": "WriteLine1"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine2"
},
"memoryReference": {
"id": "WriteLine2:input-1"
}
},
"id": "WriteLine2",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 1820,
"y": 2220
}
},
"displayText": "WriteLine2"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine3"
},
"memoryReference": {
"id": "WriteLine3:input-1"
}
},
"id": "WriteLine3",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 1820,
"y": 2400
}
},
"displayText": "WriteLine3"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine4"
},
"memoryReference": {
"id": "WriteLine4:input-1"
}
},
"id": "WriteLine4",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2060,
"y": 2160
}
},
"displayText": "WriteLine4"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine5"
},
"memoryReference": {
"id": "WriteLine5:input-1"
}
},
"id": "WriteLine5",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2060,
"y": 2320
}
},
"displayText": "WriteLine5"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine6"
},
"memoryReference": {
"id": "WriteLine6:input-1"
}
},
"id": "WriteLine6",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2060,
"y": 2480
}
},
"displayText": "WriteLine6"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine8"
},
"memoryReference": {
"id": "WriteLine8:input-1"
}
},
"id": "WriteLine8",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2340,
"y": 2400
}
},
"displayText": "WriteLine8"
}
}
],
"connections": [
{
"source": "WriteLine5",
"target": "WriteLine7",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine8",
"target": "WriteLine9",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine7",
"target": "WriteLine9",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine1",
"target": "WriteLine2",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine2",
"target": "WriteLine4",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine3",
"target": "WriteLine5",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine1",
"target": "WriteLine3",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine4",
"target": "WriteLine7",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine2",
"target": "WriteLine5",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine6",
"target": "WriteLine8",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine3",
"target": "WriteLine6",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine5",
"target": "WriteLine8",
"sourcePort": "Done",
"targetPort": "In"
}
]
}
}
@@ -0,0 +1,469 @@
{
"id": "01146119d31041c195148662710d95c7",
"definitionId": "abb565fd716f4eb7be0510ab8ff36329",
"name": "Braided delayed flow",
"createdAt": "2023-04-18T14:06:58.250625+00:00",
"version": 4,
"variables": [],
"inputs": [],
"outputs": [],
"outcomes": [],
"metadata": {},
"isLatest": true,
"isPublished": false,
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "Flowchart1",
"metadata": {},
"applicationProperties": {
"NotFoundConnectionsKey": []
},
"start": "WriteLine1",
"activities": [
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine1"
},
"memoryReference": {
"id": "WriteLine1:input-1"
}
},
"id": "WriteLine1",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 1600,
"y": 2320
}
},
"displayText": "WriteLine1"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine2"
},
"memoryReference": {
"id": "WriteLine2:input-1"
}
},
"id": "WriteLine2",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 1820,
"y": 2220
}
},
"displayText": "WriteLine2"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine3"
},
"memoryReference": {
"id": "WriteLine3:input-1"
}
},
"id": "WriteLine3",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 1820,
"y": 2400
}
},
"displayText": "WriteLine3"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine4"
},
"memoryReference": {
"id": "WriteLine4:input-1"
}
},
"id": "WriteLine4",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2060,
"y": 2160
}
},
"displayText": "WriteLine4"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine5"
},
"memoryReference": {
"id": "WriteLine5:input-1"
}
},
"id": "WriteLine5",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2060,
"y": 2320
}
},
"displayText": "WriteLine5"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine6"
},
"memoryReference": {
"id": "WriteLine6:input-1"
}
},
"id": "WriteLine6",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2060,
"y": 2480
}
},
"displayText": "WriteLine6"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine8"
},
"memoryReference": {
"id": "WriteLine8:input-1"
}
},
"id": "WriteLine8",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2460,
"y": 2400
}
},
"displayText": "WriteLine8"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine7"
},
"memoryReference": {
"id": "WriteLine7:input-1"
}
},
"id": "WriteLine7",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2460,
"y": 2240
}
},
"displayText": "WriteLine7"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine9"
},
"memoryReference": {
"id": "WriteLine9:input-1"
}
},
"id": "WriteLine9",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2680,
"y": 2300
}
},
"displayText": "WriteLine9"
}
},
{
"timeSpan": {
"typeName": "TimeSpan",
"expression": {
"type": "Literal",
"value": "00:00:05"
},
"memoryReference": {
"id": "Delay1:input-1"
}
},
"strategy": {
"typeName": "Elsa.Scheduling.Models.DelayBlockingStrategy, Elsa.Scheduling",
"expression": {
"type": "Literal",
"value": "NonBlocking"
},
"memoryReference": {
"id": "Delay1:input-2"
}
},
"autoBlockingThreshold": {
"typeName": "TimeSpan",
"expression": {
"type": "Literal",
"value": "00:00:05"
},
"memoryReference": {
"id": "Delay1:input-3"
}
},
"id": "Delay1",
"type": "Elsa.Delay",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2260,
"y": 2240
}
}
}
},
{
"timeSpan": {
"typeName": "TimeSpan",
"expression": {
"type": "Literal",
"value": "00:00:10"
},
"memoryReference": {
"id": "Delay2:input-1"
}
},
"strategy": {
"typeName": "Elsa.Scheduling.Models.DelayBlockingStrategy, Elsa.Scheduling",
"expression": {
"type": "Literal",
"value": "NonBlocking"
},
"memoryReference": {
"id": "Delay2:input-2"
}
},
"autoBlockingThreshold": {
"typeName": "TimeSpan",
"expression": {
"type": "Literal",
"value": "00:00:05"
},
"memoryReference": {
"id": "Delay2:input-3"
}
},
"id": "Delay2",
"type": "Elsa.Delay",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2280,
"y": 2440
}
}
}
}
],
"connections": [
{
"source": "WriteLine1",
"target": "WriteLine2",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine2",
"target": "WriteLine4",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine3",
"target": "WriteLine5",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine1",
"target": "WriteLine3",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine5",
"target": "WriteLine7",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine2",
"target": "WriteLine5",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine6",
"target": "Delay2",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine3",
"target": "WriteLine6",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine8",
"target": "WriteLine9",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "Delay2",
"target": "WriteLine8",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine5",
"target": "WriteLine8",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "Delay1",
"target": "WriteLine7",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine7",
"target": "WriteLine9",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine4",
"target": "Delay1",
"sourcePort": "Done",
"targetPort": "In"
}
]
}
}
@@ -0,0 +1,415 @@
{
"id": "44200e995aaf429d9975bd7177e271d0",
"definitionId": "7d0420cacaad4ae09c589a0355bbef44",
"name": "Braided conditional delayed flow",
"createdAt": "2023-04-18T14:37:02.902303+00:00",
"version": 1,
"variables": [],
"inputs": [],
"outputs": [],
"outcomes": [],
"metadata": {},
"isLatest": true,
"isPublished": false,
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "Flowchart1",
"metadata": {},
"applicationProperties": {
"NotFoundConnectionsKey": []
},
"start": "WriteLine1",
"activities": [
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine1"
},
"memoryReference": {
"id": "WriteLine1:input-1"
}
},
"id": "WriteLine1",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 1600,
"y": 2320
}
},
"displayText": "WriteLine1"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine2"
},
"memoryReference": {
"id": "WriteLine2:input-1"
}
},
"id": "WriteLine2",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 1820,
"y": 2220
}
},
"displayText": "WriteLine2"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine3"
},
"memoryReference": {
"id": "WriteLine3:input-1"
}
},
"id": "WriteLine3",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 1820,
"y": 2400
}
},
"displayText": "WriteLine3"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine4"
},
"memoryReference": {
"id": "WriteLine4:input-1"
}
},
"id": "WriteLine4",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2060,
"y": 2160
}
},
"displayText": "WriteLine4"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine6"
},
"memoryReference": {
"id": "WriteLine6:input-1"
}
},
"id": "WriteLine6",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2060,
"y": 2480
}
},
"displayText": "WriteLine6"
}
},
{
"condition": {
"typeName": "Boolean",
"expression": {
"type": "Literal",
"value": "True"
},
"memoryReference": {
"id": "FlowDecision1:input-1"
}
},
"id": "FlowDecision1",
"type": "Elsa.FlowDecision",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2060,
"y": 2320
}
}
}
},
{
"timeSpan": {
"typeName": "TimeSpan",
"expression": {
"type": "Literal",
"value": "00:00:05"
},
"memoryReference": {
"id": "Delay1:input-1"
}
},
"strategy": {
"typeName": "Elsa.Scheduling.Models.DelayBlockingStrategy, Elsa.Scheduling",
"expression": {
"type": "Literal",
"value": "NonBlocking"
},
"memoryReference": {
"id": "Delay1:input-2"
}
},
"autoBlockingThreshold": {
"typeName": "TimeSpan",
"expression": {
"type": "Literal",
"value": "00:00:05"
},
"memoryReference": {
"id": "Delay1:input-3"
}
},
"id": "Delay1",
"type": "Elsa.Delay",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2320,
"y": 2220
}
}
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine7"
},
"memoryReference": {
"id": "WriteLine7:input-1"
}
},
"id": "WriteLine7",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2520,
"y": 2220
}
},
"displayText": "WriteLine7"
}
},
{
"timeSpan": {
"typeName": "TimeSpan",
"expression": {
"type": "Literal",
"value": "00:00:10"
},
"memoryReference": {
"id": "Delay2:input-1"
}
},
"strategy": {
"typeName": "Elsa.Scheduling.Models.DelayBlockingStrategy, Elsa.Scheduling",
"expression": {
"type": "Literal",
"value": "NonBlocking"
},
"memoryReference": {
"id": "Delay2:input-2"
}
},
"autoBlockingThreshold": {
"typeName": "TimeSpan",
"expression": {
"type": "Literal",
"value": "00:00:05"
},
"memoryReference": {
"id": "Delay2:input-3"
}
},
"id": "Delay2",
"type": "Elsa.Delay",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2320,
"y": 2420
}
}
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "WriteLine8"
},
"memoryReference": {
"id": "WriteLine8:input-1"
}
},
"id": "WriteLine8",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2520,
"y": 2420
}
},
"displayText": "WriteLine8"
}
}
],
"connections": [
{
"source": "WriteLine1",
"target": "WriteLine2",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine2",
"target": "WriteLine4",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine3",
"target": "FlowDecision1",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine1",
"target": "WriteLine3",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine3",
"target": "WriteLine6",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "FlowDecision1",
"target": "Delay1",
"sourcePort": "True",
"targetPort": "In"
},
{
"source": "WriteLine2",
"target": "FlowDecision1",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "Delay1",
"target": "WriteLine7",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "Delay2",
"target": "WriteLine8",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "FlowDecision1",
"target": "Delay2",
"sourcePort": "False",
"targetPort": "In"
}
]
}
}
@@ -0,0 +1,207 @@
{
"id": "3365d4c0198e459f834b799cbfe91154",
"definitionId": "4aa1e566da264ab6b5495bedb734096d",
"name": "Forking, Containment and Blocking",
"description": "A combination of a fork, a containment and a blocking activity.",
"version": 1,
"toolVersion": "3.0.0.0",
"variables": [],
"inputs": [],
"outputs": [],
"outcomes": [],
"customProperties": {},
"isReadonly": false,
"isLatest": true,
"isPublished": true,
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "uEnFWEdaWkadgIMHT2umLA",
"metadata": {},
"customProperties": {
"NotFoundConnectionsKey": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"activities": [
{
"id": "MLDV_altcUO5MwP7p5xJWw",
"name": "Start1",
"type": "Elsa.Start",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -480,
"y": -566.046875
},
"size": {
"width": 102.21875,
"height": 50
}
}
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "Intermediary"
},
"memoryReference": {
"id": "EIh3Q0Um1U-QSCh1b3GBjQ:input-0"
}
},
"id": "EIh3Q0Um1U-QSCh1b3GBjQ",
"name": "WriteLine1",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -228.5,
"y": -476.046875
},
"size": {
"width": 139.296875,
"height": 50
}
}
}
},
{
"text": null,
"id": "0Z7Velr5CEW_r7YYoeEjBQ",
"name": "WriteLine2",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 69.34375,
"y": -476.046875
},
"size": {
"width": 139.296875,
"height": 50
}
}
}
},
{
"body": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "NJ5fh2bUWU-TxWeXsbNaSg",
"metadata": {},
"customProperties": {
"NotFoundConnectionsKey": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"activities": [
{
"eventName": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "Event4"
},
"memoryReference": {
"id": "8KVHRw-WpUizyxOq0C6Nvg:input-0"
}
},
"result": null,
"id": "8KVHRw-WpUizyxOq0C6Nvg",
"name": "Event1",
"type": "Elsa.Event",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -840,
"y": -500
},
"size": {
"width": 106.828125,
"height": 50
}
}
}
}
],
"connections": []
},
"id": "HG4wfBhvlEW_149HwNyzHw",
"name": "FlowNode1",
"type": "Elsa.FlowNode",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -228.5,
"y": -704.109375
},
"size": {
"width": 211.15625,
"height": 120
}
}
}
}
],
"connections": [
{
"source": {
"activity": "MLDV_altcUO5MwP7p5xJWw",
"port": "Done"
},
"target": {
"activity": "HG4wfBhvlEW_149HwNyzHw",
"port": "In"
}
},
{
"source": {
"activity": "MLDV_altcUO5MwP7p5xJWw",
"port": "Done"
},
"target": {
"activity": "EIh3Q0Um1U-QSCh1b3GBjQ",
"port": "In"
}
},
{
"source": {
"activity": "EIh3Q0Um1U-QSCh1b3GBjQ",
"port": "Done"
},
"target": {
"activity": "0Z7Velr5CEW_r7YYoeEjBQ",
"port": "In"
}
}
]
}
}
@@ -0,0 +1,198 @@
{
"id": "e5190066597846cc926f8ae644d706f4",
"definitionId": "b07725956291433abee7ff229b415194",
"name": "Parallel For Each",
"createdAt": "2023-09-10T16:32:58.422674+00:00",
"version": 3,
"toolVersion": "3.0.0.0",
"variables": [],
"inputs": [],
"outputs": [],
"outcomes": [],
"customProperties": {},
"isReadonly": false,
"isLatest": true,
"isPublished": true,
"options": {
"autoUpdateConsumingWorkflows": false
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "oplDmRa_zEqH8PCdTcFh8A",
"metadata": {},
"customProperties": {
"source": "FlowchartJsonConverter.cs:45",
"NotFoundConnectionsKey": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"activities": [
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "Start"
},
"memoryReference": {
"id": "NTW8X70bTEaBtlYyU44PcA:input-0"
}
},
"id": "NTW8X70bTEaBtlYyU44PcA",
"name": "WriteLine1",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -352,
"y": -286.9921875
},
"size": {
"width": 139.296875,
"height": 50
}
}
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "End"
},
"memoryReference": {
"id": "6Bf011ZOvUWOfQ1rKJEDFA:input-0"
}
},
"id": "6Bf011ZOvUWOfQ1rKJEDFA",
"name": "WriteLine2",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 169,
"y": -286.9921875
},
"size": {
"width": 139.296875,
"height": 50
}
}
}
},
{
"items": {
"typeName": "Object[]",
"expression": {
"type": "JavaScript",
"value": "[\u0022Apple\u0022, \u0022Banana\u0022, \u0022Cherry\u0022]"
},
"memoryReference": {
"id": "By4rVs_-2kSDENFO-bniRg:input-0"
}
},
"body": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "ylZLDh7FQ0WmnbdnRJHutg",
"metadata": {},
"customProperties": {
"source": "FlowchartJsonConverter.cs:45",
"NotFoundConnectionsKey": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"activities": [
{
"text": {
"typeName": "String",
"expression": {
"type": "JavaScript",
"value": "\u0060Current fruit: ${getCurrentValue()}\u0060"
},
"memoryReference": {
"id": "fht2JVY0G0KURaRYB9jqlw:input-0"
}
},
"id": "fht2JVY0G0KURaRYB9jqlw",
"name": "WriteLine1",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -459.5,
"y": -374
},
"size": {
"width": 139.296875,
"height": 50
}
}
}
}
],
"connections": []
},
"id": "By4rVs_-2kSDENFO-bniRg",
"name": "ParallelForEach1",
"type": "Elsa.ParallelForEach",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -100,
"y": -320
},
"size": {
"width": 149.203125,
"height": 116.015625
}
}
}
}
],
"connections": [
{
"source": {
"activity": "NTW8X70bTEaBtlYyU44PcA",
"port": "Done"
},
"target": {
"activity": "By4rVs_-2kSDENFO-bniRg",
"port": "In"
}
},
{
"source": {
"activity": "By4rVs_-2kSDENFO-bniRg",
"port": "Done"
},
"target": {
"activity": "6Bf011ZOvUWOfQ1rKJEDFA",
"port": "In"
}
}
]
}
}
@@ -0,0 +1,9 @@
namespace Elsa.Workflows.IntegrationTests.Scenarios.FlowchartNextActivity.Activities;
public class CustomActivity : CodeActivity
{
protected override async ValueTask ExecuteAsync(ActivityExecutionContext context)
{
await context.CompleteActivityAsync();
}
}
@@ -0,0 +1,315 @@
using Elsa.Expressions.Models;
using Elsa.Testing.Shared;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Activities.Flowchart.Activities;
using Elsa.Workflows.Activities.Flowchart.Models;
using Elsa.Workflows.IntegrationTests.Scenarios.FlowchartNextActivity.Workflows;
using Elsa.Workflows.Memory;
using Microsoft.Extensions.DependencyInjection;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.FlowchartNextActivity;
public class FlowchartNextActivityTests
{
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly IServiceProvider _services;
private readonly IWorkflowRunner _workflowRunner;
public FlowchartNextActivityTests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper)
.WithCapturingTextWriter(_capturingTextWriter)
.AddActivitiesFrom<FlowchartNextActivityTests>()
.Build();
_workflowRunner = _services.GetRequiredService<IWorkflowRunner>();
}
[Fact(DisplayName = "Flowchart only schedules next activity connected to outcome of previous activity.")]
public async Task Test1()
{
await _services.PopulateRegistriesAsync();
await _workflowRunner.RunAsync<FlowchartWorkflow>();
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(new[] { "Line 1" }, lines);
}
[Fact(DisplayName = "Flowchart with backward connections and a dangling activity")]
public async Task BackwardConnectionTest()
{
var workflow = new TestWorkflow(workflowBuilder =>
{
var loopVariable = new Variable<int>("LoopCount", 0);
var start = new Start();
var dangling = new WriteLine("dangling");
var writeLineDecision = new FlowSwitch()
{
Cases = {
new FlowSwitchCase("LessThanThree", new Expression("JavaScript", "getVariable('LoopCount') < 3")),
new FlowSwitchCase("LessThanOne", new Expression("JavaScript", "getVariable('LoopCount') < 1")),
},
Mode = new(SwitchMode.MatchAny)
};
var a = new WriteLine("A");
var b = new WriteLine("B");
var c = new WriteLine("C");
var incrementLoop = new SetVariable()
{
Variable = loopVariable,
Value = new Models.Input<object?>(new Expression("JavaScript", "getVariable('LoopCount') + 1"))
};
var loopbackDecision = new FlowSwitch()
{
Cases = {
new FlowSwitchCase("EqualOne", new Expression("JavaScript", "getVariable('LoopCount') == 1")),
new FlowSwitchCase("LessThanFour", new Expression("JavaScript", "getVariable('LoopCount') < 4")),
},
Mode = new(SwitchMode.MatchFirst)
};
var d = new WriteLine("D");
var e = new WriteLine("E");
var f = new WriteLine("F");
var end = new End();
workflowBuilder.Root = new Flowchart
{
Variables =
{
loopVariable
},
Activities =
{
start,
dangling,
writeLineDecision,
a,
b,
c,
incrementLoop,
loopbackDecision,
d,
e,
f,
end
},
Connections =
{
new(start, writeLineDecision),
new(dangling, writeLineDecision),
new(new Endpoint(writeLineDecision, "LessThanThree"), new Endpoint(a)),
new(new Endpoint(writeLineDecision, "LessThanThree"), new Endpoint(b)),
new(new Endpoint(writeLineDecision, "LessThanOne"), new Endpoint(c)),
new(new Endpoint(writeLineDecision, "Default"), new Endpoint(incrementLoop)),
new(a, incrementLoop),
new(b, incrementLoop),
new(c, incrementLoop),
new(incrementLoop, loopbackDecision),
new(new Endpoint(loopbackDecision, "EqualOne"), new Endpoint(d)),
new(d, incrementLoop),
new(new Endpoint(loopbackDecision, "LessThanFour"), new Endpoint(e)),
new(e, writeLineDecision),
new(new Endpoint(loopbackDecision, "Default"), new Endpoint(f)),
new(f, end),
}
};
});
await _services.PopulateRegistriesAsync();
var result = await _workflowRunner.RunAsync(workflow);
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(WorkflowSubStatus.Finished, result.WorkflowState.SubStatus);
Assert.Equal(new[] { "A", "B", "C", "D", "E", "A", "B", "E", "F" }, lines);
}
[Fact(DisplayName = "Flowchart with an invalid backward connection")]
public async Task InvalidBackwardConnectionTest()
{
var workflow = new TestWorkflow(workflowBuilder =>
{
var start = new Start() { Id = "Start" };
var a = new WriteLine("A") { Id = "WriteLineA" };
var b = new WriteLine("B") { Id = "WriteLineB" };
var c = new WriteLine("C") { Id = "WriteLineC" };
var d = new WriteLine("D") { Id = "WriteLineD" };
var e = new WriteLine("E") { Id = "WriteLineE" };
workflowBuilder.Root = new Flowchart
{
Activities =
{
start,
a,
b,
c,
d,
e,
},
Connections =
{
new(start, a),
new(a, b),
new(b, c),
new(b, d),
new(c, e),
new(d, e),
new(e, c),
}
};
});
await _services.PopulateRegistriesAsync();
var result = await _workflowRunner.RunAsync(workflow);
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(WorkflowSubStatus.Faulted, result.WorkflowState.SubStatus);
Assert.Equal(1, result.WorkflowState.Incidents.Count());
Assert.Equal("Invalid backward connection: Every path from the source ('WriteLineE') must go through the target ('WriteLineC') when tracing back to the start.", result.WorkflowState.Incidents.First().Message);
Assert.Equal(new[] { "A", "B", "C", "D", "E" }, lines);
}
[Theory(DisplayName = "Flowchart with a Join activity executed multiple times")]
[InlineData(FlowJoinMode.WaitAll)]
[InlineData(FlowJoinMode.WaitAny)]
public async Task WaitAnyLoopTest(FlowJoinMode joinMode)
{
var workflow = new TestWorkflow(workflowBuilder =>
{
var loopVariable = new Variable<int>("LoopCount", 0);
var start = new Start();
var a = new WriteLine("A");
var b = new WriteLine("B");
var c = new WriteLine("C");
var d = new WriteLine("D");
var join = new FlowJoin()
{
Mode = new(joinMode)
};
var incrementLoop = new SetVariable()
{
Variable = loopVariable,
Value = new Models.Input<object?>(new Expression("JavaScript", "getVariable('LoopCount') + 1"))
};
var loopbackDecision = new FlowSwitch()
{
Cases = {
new FlowSwitchCase("LessThanThree", new Expression("JavaScript", "getVariable('LoopCount') < 3")),
},
Mode = new(SwitchMode.MatchFirst)
};
var end = new End();
workflowBuilder.Root = new Flowchart
{
Variables =
{
loopVariable
},
Activities =
{
start,
a,
b,
c,
d,
join,
incrementLoop,
loopbackDecision,
end
},
Connections =
{
new(start, a),
new(a, b),
new(a, c),
new(a, d),
new(b, join),
new(c, join),
new(d, join),
new(join, incrementLoop),
new(incrementLoop,loopbackDecision),
new(new Endpoint(loopbackDecision, "LessThanThree"), new Endpoint(a)),
new(new Endpoint(loopbackDecision, "Default"), new Endpoint(end)),
}
};
});
await _services.PopulateRegistriesAsync();
var result = await _workflowRunner.RunAsync(workflow);
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(WorkflowSubStatus.Finished, result.WorkflowState.SubStatus);
Assert.Equal(new[] { "A", "B", "C", "D", "A", "B", "C", "D", "A", "B", "C", "D"}, lines);
}
[Theory(DisplayName = "Flowchart with a Join activity executed multiple times, bug 6479")]
[InlineData(FlowJoinMode.WaitAll)]
[InlineData(FlowJoinMode.WaitAny)]
public async Task WaitLoopBug6479Test(FlowJoinMode joinMode)
{
var workflow = new TestWorkflow(workflowBuilder =>
{
var loopVariable = new Variable<int>("LoopCount", 0);
var start = new Start();
var loopbackSwitch = new FlowSwitch()
{
Cases = {
new FlowSwitchCase("DoLoopback", new Expression("JavaScript", "getVariable('LoopCount') < 3")),
},
Mode = new(SwitchMode.MatchFirst)
};
var a = new WriteLine("A");
var incrementLoop = new SetVariable()
{
Variable = loopVariable,
Value = new Models.Input<object?>(new Expression("JavaScript", "getVariable('LoopCount') + 1"))
};
var join = new FlowJoin()
{
Mode = new(joinMode)
};
var b = new WriteLine("B");
var end = new End();
workflowBuilder.Root = new Flowchart
{
Variables =
{
loopVariable
},
Activities =
{
start,
loopbackSwitch,
a,
incrementLoop,
join,
b,
end
},
Connections =
{
new(start, loopbackSwitch),
new(new Endpoint(loopbackSwitch, "DoLoopback"), new Endpoint(a)),
new(new Endpoint(loopbackSwitch, "DoLoopback"), new Endpoint(incrementLoop)),
new(new Endpoint(loopbackSwitch, "Default"), new Endpoint(b)),
new(a, join),
new(incrementLoop, join),
new(join, loopbackSwitch),
new(b, end),
}
};
});
await _services.PopulateRegistriesAsync();
var result = await _workflowRunner.RunAsync(workflow);
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(WorkflowSubStatus.Finished, result.WorkflowState.SubStatus);
Assert.Equal(new[] { "A", "A", "A", "B" }, lines);
}
}
@@ -0,0 +1,31 @@
using Elsa.Workflows.Activities;
using Elsa.Workflows.Activities.Flowchart.Activities;
using Elsa.Workflows.Activities.Flowchart.Models;
using Elsa.Workflows.IntegrationTests.Scenarios.FlowchartNextActivity.Activities;
namespace Elsa.Workflows.IntegrationTests.Scenarios.FlowchartNextActivity.Workflows;
public class FlowchartWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder builder)
{
var customActivity = new CustomActivity();
var writeLine1 = new WriteLine("Line 1");
var writeLine2 = new WriteLine("Line 2");
builder.Root = new Flowchart
{
Activities =
{
customActivity,
writeLine1,
writeLine2
},
Connections =
{
new Connection(new Endpoint(customActivity, "Done"), new Endpoint(writeLine1)),
new Connection(new Endpoint(customActivity, "Fake"), new Endpoint(writeLine2)),
}
};
}
}
@@ -0,0 +1,40 @@
using Elsa.Expressions.Models;
using Elsa.JavaScript.Activities;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Memory;
namespace Elsa.Workflows.IntegrationTests.Scenarios.HttpRequestWithLiquid;
/// <summary>
/// A workflow that use javascript to get some data, use them with some liquid expressions
/// </summary>
public class JavascriptAndLiquidWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder builder)
{
var products = new Variable<object>("Products", null!).WithStorageDriver<WorkflowInstanceStorageDriver>();
var product = new Variable<object>("Product", null!).WithStorageDriver<WorkflowInstanceStorageDriver>();
builder.Root = new Sequence
{
Variables = { products, product },
Activities =
{
new RunJavaScript
{
Script = new(@"setProducts([{""id"":1, ""price"":12.99}, {""id"":2, ""price"":10}, {""id"":3, ""price"":1}])")
},
new WriteLine(new Expression("Liquid", "First product id: {{ Variables.Products[0].id }}")),
new WriteLine(new Expression("Liquid", "First product price rounded: {{ Variables.Products[0].price | round }}")),
new WriteLine(new Expression("Liquid", "First product as json: {{ Variables.Products[0] | json }}")),
new WriteLine(new Expression("Liquid", "Second product id: {{ Variables.Products[1].id }}")),
new RunJavaScript
{
Script = new(@"variables.Product = {""id"":2, ""price"":10}")
},
new WriteLine(new Expression("Liquid", "Single product id: {{ Variables.Product.id }}")),
new WriteLine(new Expression("Liquid", "Single product as json: {{ Variables.Product | json }}")),
}
};
}
}
@@ -0,0 +1,48 @@
using Elsa.Extensions;
using Elsa.Testing.Shared;
using Elsa.Workflows.Models;
using Microsoft.Extensions.DependencyInjection;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.HttpRequestWithLiquid;
public sealed class Tests : IDisposable
{
private readonly IWorkflowRunner _workflowRunner;
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly IServiceProvider _services;
public Tests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper)
.WithCapturingTextWriter(_capturingTextWriter)
.ConfigureElsa(configure => configure.UseHttp())
.Build();
_workflowRunner = _services.GetRequiredService<IWorkflowRunner>();
}
[Fact]
public async Task GetProducts()
{
await _services.PopulateRegistriesAsync();
RunWorkflowResult result = await _workflowRunner.RunAsync(new JavascriptAndLiquidWorkflow());
Assert.Equal(WorkflowStatus.Finished, result.WorkflowState.Status);
Assert.Empty(result.WorkflowState.Incidents);
Assert.Equal(WorkflowSubStatus.Finished, result.WorkflowState.SubStatus);
var lines = _capturingTextWriter.Lines.ToList();
Assert.Contains("First product id: 1", lines);
Assert.Contains("First product price rounded: 13", lines);
Assert.Contains("First product as json: {\"id\":1,\"price\":12.99}", lines);
Assert.Contains("Second product id: 2", lines);
Assert.Contains("Single product id: 2", lines);
Assert.Contains("Single product as json: {\"id\":2,\"price\":10}", lines);
}
public void Dispose()
{
_capturingTextWriter.Dispose();
GC.SuppressFinalize(this);
}
}
@@ -0,0 +1,36 @@
using Elsa.Testing.Shared;
using Elsa.Workflows.IntegrationTests.Scenarios.ImplicitJoins.Workflows;
using Microsoft.Extensions.DependencyInjection;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.ImplicitJoins;
public class BraidedWorkflowTests
{
private readonly IWorkflowRunner _workflowRunner;
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly IServiceProvider _services;
public BraidedWorkflowTests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper).WithCapturingTextWriter(_capturingTextWriter).Build();
_workflowRunner = _services.GetRequiredService<IWorkflowRunner>();
}
[Fact(DisplayName = "Braided workflows are executed correctly")]
public async Task Test1()
{
await _services.PopulateRegistriesAsync();
await _workflowRunner.RunAsync<BraidedWorkflow>();
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(new[] { "WriteLine1", "WriteLine2", "WriteLine3", "WriteLine4", "WriteLine5", "WriteLine6", "WriteLine7" }, lines);
}
[Fact(DisplayName = "Braided workflows complete the workflow")]
public async Task Test2()
{
await _services.PopulateRegistriesAsync();
var result = await _workflowRunner.RunAsync<BraidedWorkflow>();
Assert.Equal(WorkflowStatus.Finished, result.WorkflowState.Status);
}
}
@@ -0,0 +1,36 @@
using Elsa.Testing.Shared;
using Elsa.Workflows.IntegrationTests.Scenarios.ImplicitJoins.Workflows;
using Microsoft.Extensions.DependencyInjection;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.ImplicitJoins;
public class ImplicitWorkflowTests
{
private readonly IWorkflowRunner _workflowRunner;
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly IServiceProvider _services;
public ImplicitWorkflowTests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper).WithCapturingTextWriter(_capturingTextWriter).Build();
_workflowRunner = _services.GetRequiredService<IWorkflowRunner>();
}
[Fact(DisplayName = "Implicit loop workflows are executed correctly")]
public async Task Test1()
{
await _services.PopulateRegistriesAsync();
await _workflowRunner.RunAsync<ImplicitLoopWorkflow>();
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(new[] { "Start", "Retry", "End" }, lines);
}
[Fact(DisplayName = "Implicit loop workflows complete the workflow")]
public async Task Test2()
{
await _services.PopulateRegistriesAsync();
var result = await _workflowRunner.RunAsync<ImplicitLoopWorkflow>();
Assert.Equal(WorkflowStatus.Finished, result.WorkflowState.Status);
}
}
@@ -0,0 +1,42 @@
using Elsa.Common.Models;
using Elsa.Testing.Shared;
using Elsa.Workflows.Runtime;
using Elsa.Workflows.Runtime.Filters;
using Microsoft.Extensions.DependencyInjection;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.ImplicitJoins;
public class JoinRunsOnceTests
{
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly IServiceProvider _services;
public JoinRunsOnceTests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper).WithCapturingTextWriter(_capturingTextWriter).Build();
}
[Fact(DisplayName = "The Join activity executes only once, not twice")]
public async Task Test1()
{
// Populate registries.
await _services.PopulateRegistriesAsync();
// Import workflow.
var workflowDefinition = await _services.ImportWorkflowDefinitionAsync($"Scenarios/ImplicitJoins/Workflows/join.json");
// Execute.
var state = await _services.RunWorkflowUntilEndAsync(workflowDefinition.DefinitionId);
// Assert.
var journal = await _services.GetRequiredService<IWorkflowExecutionLogStore>().FindManyAsync(new WorkflowExecutionLogRecordFilter
{
WorkflowInstanceId = state.Id,
ActivityId = "802725996be1b582",
EventName = "Completed"
}, PageArgs.All);
Assert.Single(journal.Items);
}
}
@@ -0,0 +1,42 @@
using Elsa.Common.Models;
using Elsa.Testing.Shared;
using Elsa.Workflows.Runtime;
using Elsa.Workflows.Runtime.Filters;
using Microsoft.Extensions.DependencyInjection;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.ImplicitJoins;
public class ParallelJoinCompletesTests
{
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly IServiceProvider _services;
public ParallelJoinCompletesTests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper).WithCapturingTextWriter(_capturingTextWriter).Build();
}
[Fact(DisplayName = "The ParallelForEach activity completes when its Body contains a Join activity")]
public async Task Test1()
{
// Populate registries.
await _services.PopulateRegistriesAsync();
// Import workflow.
var workflowDefinition = await _services.ImportWorkflowDefinitionAsync("Scenarios/ImplicitJoins/Workflows/parallel-join.json");
// Execute.
var state = await _services.RunWorkflowUntilEndAsync(workflowDefinition.DefinitionId);
// Assert.
var journal = await _services.GetRequiredService<IWorkflowExecutionLogStore>().FindManyAsync(new()
{
WorkflowInstanceId = state.Id,
ActivityId = "70fc1183cd5800f2",
EventName = "Completed"
}, PageArgs.All);
Assert.Single(journal.Items);
}
}
@@ -0,0 +1,51 @@
using Elsa.Workflows.Activities;
using Elsa.Workflows.Activities.Flowchart.Activities;
using Elsa.Workflows.Activities.Flowchart.Models;
namespace Elsa.Workflows.IntegrationTests.Scenarios.ImplicitJoins.Workflows;
public class BraidedWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder workflow)
{
var writeLine1 = new WriteLine("WriteLine1");
var writeLine2 = new WriteLine("WriteLine2");
var writeLine3 = new WriteLine("WriteLine3");
var writeLine4 = new WriteLine("WriteLine4");
var writeLine5 = new WriteLine("WriteLine5");
var writeLine6 = new WriteLine("WriteLine6");
var writeLine7 = new WriteLine("WriteLine7");
workflow.Root = new Flowchart
{
Start = writeLine1,
Activities =
{
writeLine1,
writeLine2,
writeLine3,
writeLine4,
writeLine5,
writeLine6,
writeLine7,
},
Connections =
{
new Connection(writeLine1, writeLine2),
new Connection(writeLine1, writeLine3),
new Connection(writeLine2, writeLine4),
new Connection(writeLine2, writeLine5),
new Connection(writeLine3, writeLine5),
new Connection(writeLine3, writeLine6),
new Connection(writeLine4, writeLine7),
new Connection(writeLine5, writeLine7),
new Connection(writeLine6, writeLine7),
}
};
}
}
@@ -0,0 +1,41 @@
using Elsa.Workflows.Activities;
using Elsa.Workflows.Activities.Flowchart.Activities;
using Elsa.Workflows.Activities.Flowchart.Models;
namespace Elsa.Workflows.IntegrationTests.Scenarios.ImplicitJoins.Workflows;
public class ImplicitLoopWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder builder)
{
var counterVariable = builder.WithVariable(0);
var start = new WriteLine("Start");
var incrementCounter = new SetVariable<int>(counterVariable, context => counterVariable.Get(context) + 1);
var counterGreaterThanOne = new FlowDecision(context => counterVariable.Get(context) > 1);
var retry = new WriteLine("Retry");
var end = new WriteLine("End");
builder.Root = new Flowchart
{
Start = start,
Activities =
{
start,
incrementCounter,
counterGreaterThanOne,
retry,
end
},
Connections =
{
new Connection(start, incrementCounter),
new Connection(incrementCounter, counterGreaterThanOne),
new Connection(new Endpoint(counterGreaterThanOne, "False"), new Endpoint(retry)),
new Connection(new Endpoint(counterGreaterThanOne, "True"), new Endpoint(end)),
new Connection(retry, incrementCounter),
}
};
}
}
@@ -0,0 +1,215 @@
{
"id": "825e9d347e2f3094",
"definitionId": "f64e42304661f407",
"name": "Joins",
"createdAt": "2023-12-13T21:41:53.628415+00:00",
"version": 3,
"toolVersion": "3.0.0.0",
"variables": [],
"inputs": [],
"outputs": [],
"outcomes": [],
"customProperties": {
"Elsa:WorkflowContextProviderTypes": []
},
"isReadonly": false,
"isLatest": true,
"isPublished": false,
"options": {
"autoUpdateConsumingWorkflows": false
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "8a03bf79d15fd48a",
"nodeId": "Workflow1:8a03bf79d15fd48a",
"metadata": {},
"customProperties": {
"source": "FlowchartJsonConverter.cs:45",
"notFoundConnections": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"activities": [
{
"id": "c7624645ff77c7d0",
"nodeId": "Workflow1:8a03bf79d15fd48a:c7624645ff77c7d0",
"name": "Start1",
"type": "Elsa.Start",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -400.5,
"y": 212
},
"size": {
"width": 102.21875,
"height": 50
}
}
}
},
{
"text": null,
"id": "281e9ea6d278b231",
"nodeId": "Workflow1:8a03bf79d15fd48a:281e9ea6d278b231",
"name": "WriteLine2",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -160.5,
"y": 305
},
"size": {
"width": 139.296875,
"height": 50
}
}
}
},
{
"mode": {
"typeName": "Elsa.Workflows.Core.Activities.Flowchart.Models.FlowJoinMode, Elsa.Workflows.Core",
"expression": {
"type": "Literal",
"value": "WaitAny"
},
"memoryReference": {
"id": "802725996be1b582:input-0"
}
},
"id": "802725996be1b582",
"nodeId": "Workflow1:8a03bf79d15fd48a:802725996be1b582",
"name": "FlowJoin1",
"type": "Elsa.FlowJoin",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 80,
"y": 200
},
"size": {
"width": 98.265625,
"height": 50
}
}
}
},
{
"text": null,
"id": "bfc88f064cf394ed",
"nodeId": "Workflow1:8a03bf79d15fd48a:bfc88f064cf394ed",
"name": "WriteLine1",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -160,
"y": 120
},
"size": {
"width": 139.296875,
"height": 50
}
}
}
},
{
"id": "5467123c7973d011",
"nodeId": "Workflow1:8a03bf79d15fd48a:5467123c7973d011",
"name": "End1",
"type": "Elsa.End",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 274.5,
"y": 200
},
"size": {
"width": 94.40625,
"height": 50
}
}
}
}
],
"connections": [
{
"source": {
"activity": "c7624645ff77c7d0",
"port": "Done"
},
"target": {
"activity": "bfc88f064cf394ed",
"port": "In"
}
},
{
"source": {
"activity": "bfc88f064cf394ed",
"port": "Done"
},
"target": {
"activity": "802725996be1b582",
"port": "In"
}
},
{
"source": {
"activity": "c7624645ff77c7d0",
"port": "Done"
},
"target": {
"activity": "281e9ea6d278b231",
"port": "In"
}
},
{
"source": {
"activity": "281e9ea6d278b231",
"port": "Done"
},
"target": {
"activity": "802725996be1b582",
"port": "In"
}
},
{
"source": {
"activity": "802725996be1b582",
"port": "Done"
},
"target": {
"activity": "5467123c7973d011",
"port": "In"
}
}
]
}
}
@@ -0,0 +1,241 @@
{
"id": "2effd8f5f4205a5b",
"definitionId": "2da8d4cb0fcfbacd",
"name": "Parallel \u002B Join",
"createdAt": "2023-12-13T21:42:12.634042+00:00",
"version": 2,
"toolVersion": "3.0.0.0",
"variables": [],
"inputs": [],
"outputs": [],
"outcomes": [],
"customProperties": {
"Elsa:WorkflowContextProviderTypes": []
},
"isReadonly": false,
"isLatest": true,
"isPublished": false,
"options": {
"autoUpdateConsumingWorkflows": false
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "d3350290ed96e720",
"nodeId": "Workflow1:d3350290ed96e720",
"metadata": {},
"customProperties": {
"source": "FlowchartJsonConverter.cs:45",
"notFoundConnections": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"activities": [
{
"items": {
"typeName": "Object[]",
"expression": {
"type": "JavaScript",
"value": "[1,2,3]"
},
"memoryReference": {
"id": "70fc1183cd5800f2:input-0"
}
},
"body": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "b07170f2d68980cd",
"nodeId": "Workflow1:d3350290ed96e720:70fc1183cd5800f2:b07170f2d68980cd",
"metadata": {},
"customProperties": {
"source": "FlowchartJsonConverter.cs:45",
"notFoundConnections": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"activities": [
{
"condition": {
"typeName": "Boolean",
"expression": {
"type": "JavaScript",
"value": "false"
},
"memoryReference": {
"id": "33665f061d96b957:input-0"
}
},
"id": "33665f061d96b957",
"nodeId": "Workflow1:d3350290ed96e720:70fc1183cd5800f2:b07170f2d68980cd:33665f061d96b957",
"name": "FlowDecision1",
"type": "Elsa.FlowDecision",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -329.140625,
"y": -78.5
},
"size": {
"width": 129.515625,
"height": 50
}
}
}
},
{
"text": null,
"id": "e27177eb5965bd6b",
"nodeId": "Workflow1:d3350290ed96e720:70fc1183cd5800f2:b07170f2d68980cd:e27177eb5965bd6b",
"name": "WriteLine1",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -40,
"y": -160
},
"size": {
"width": 139.296875,
"height": 50
}
}
}
},
{
"text": null,
"id": "343d233a75d8d8e9",
"nodeId": "Workflow1:d3350290ed96e720:70fc1183cd5800f2:b07170f2d68980cd:343d233a75d8d8e9",
"name": "WriteLine2",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 371.859375,
"y": -78.5
},
"size": {
"width": 139.296875,
"height": 50
}
}
}
},
{
"mode": {
"typeName": "Elsa.Workflows.Core.Activities.Flowchart.Models.FlowJoinMode, Elsa.Workflows.Core",
"expression": {
"type": "Literal",
"value": "WaitAny"
},
"memoryReference": {
"id": "1f8625e278b74aa3:input-0"
}
},
"id": "1f8625e278b74aa3",
"nodeId": "Workflow1:d3350290ed96e720:70fc1183cd5800f2:b07170f2d68980cd:1f8625e278b74aa3",
"name": "FlowJoin1",
"type": "Elsa.FlowJoin",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 188.859375,
"y": -78.5
},
"size": {
"width": 98.265625,
"height": 50
}
}
}
}
],
"connections": [
{
"source": {
"activity": "33665f061d96b957",
"port": "True"
},
"target": {
"activity": "e27177eb5965bd6b",
"port": "In"
}
},
{
"source": {
"activity": "e27177eb5965bd6b",
"port": "Done"
},
"target": {
"activity": "1f8625e278b74aa3",
"port": "In"
}
},
{
"source": {
"activity": "1f8625e278b74aa3",
"port": "Done"
},
"target": {
"activity": "343d233a75d8d8e9",
"port": "In"
}
},
{
"source": {
"activity": "33665f061d96b957",
"port": "False"
},
"target": {
"activity": "1f8625e278b74aa3",
"port": "In"
}
}
]
},
"id": "70fc1183cd5800f2",
"nodeId": "Workflow1:d3350290ed96e720:70fc1183cd5800f2",
"name": "ParallelForEach1",
"type": "Elsa.ParallelForEach",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -260,
"y": 140
},
"size": {
"width": 185.203125,
"height": 116.015625
}
}
}
}
],
"connections": []
}
}
@@ -0,0 +1,45 @@
using Elsa.Testing.Shared;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.ImportAndExecute;
public class Tests
{
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly IServiceProvider _services;
public Tests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper)
.WithCapturingTextWriter(_capturingTextWriter)
.Build();
}
[Theory(DisplayName = "Workflow imported from file should execute successfully.")]
[MemberData(memberName: nameof(GetSpecimen))]
public async Task Test1(string workflowFileName, string[] expectedOutput)
{
// Populate registries.
await _services.PopulateRegistriesAsync();
// Import workflow.
var workflowDefinition = await _services.ImportWorkflowDefinitionAsync($"Scenarios/ImportAndExecute/Workflows/{workflowFileName}");
// Execute.
await _services.RunWorkflowUntilEndAsync(workflowDefinition.DefinitionId);
// Assert.
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(expectedOutput, lines);
}
public static TheoryData<string, string[]> GetSpecimen()
{
return new TheoryData<string, string[]>
{
{ "writeline.json", new[] { "Dummy Text" } },
{ "implicit-loop.json", new[] { "Do something", "Retry", "Do something", "Done" } }
};
}
}
@@ -0,0 +1,243 @@
{
"id": "0975a7e7cff7421ea03d1cc0247db02b",
"definitionId": "68e6bca3d86c4a5a8dfb825f1d5c0875",
"name": "Looping construct",
"createdAt": "2023-04-18T19:04:50.945222+00:00",
"version": 1,
"variables": [
{
"id": "b1198ecccf3f435abe462dc37012cda9",
"name": "Counter",
"typeName": "Int32",
"isArray": false,
"value": "0",
"storageDriverTypeName": "Elsa.Workflows.Services.WorkflowStorageDriver, Elsa.Workflows.Core"
}
],
"inputs": [],
"outputs": [],
"outcomes": [],
"metadata": {},
"isLatest": true,
"isPublished": true,
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "Flowchart1",
"metadata": {},
"applicationProperties": {
"NotFoundConnectionsKey": []
},
"start": "Start1",
"activities": [
{
"variable": {
"id": "b1198ecccf3f435abe462dc37012cda9",
"name": "Counter",
"typeName": "Int32",
"value": "0",
"storageDriverTypeName": "Elsa.Workflows.Services.WorkflowStorageDriver, Elsa.Workflows.Core"
},
"value": {
"typeName": "Object",
"expression": {
"type": "JavaScript",
"value": "getCounter() \u002B 1"
},
"memoryReference": {
"id": "SetVariable1:input-1"
}
},
"id": "SetVariable1",
"type": "Elsa.SetVariable",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2620,
"y": 2280
}
},
"displayText": "Increment counter"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "Done"
},
"memoryReference": {
"id": "WriteLine3:input-1"
}
},
"id": "WriteLine3",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 3220,
"y": 2400
}
},
"displayText": "Done"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "Retry"
},
"memoryReference": {
"id": "WriteLine2:input-1"
}
},
"id": "WriteLine2",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2460,
"y": 2500
}
},
"displayText": "Retry"
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "Do something"
},
"memoryReference": {
"id": "WriteLine1:input-1"
}
},
"id": "WriteLine1",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2320,
"y": 2280
}
},
"displayText": "Do something"
}
},
{
"condition": {
"typeName": "Boolean",
"expression": {
"type": "JavaScript",
"value": "getCounter() \u003E 1"
},
"memoryReference": {
"id": "FlowDecision1:input-1"
}
},
"id": "FlowDecision1",
"type": "Elsa.FlowDecision",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2940,
"y": 2400
}
},
"displayText": "Counter \u003E 1"
}
},
{
"id": "Start1",
"type": "Elsa.Start",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2060,
"y": 2380
}
}
}
}
],
"connections": [
{
"source": "WriteLine1",
"target": "SetVariable1",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "FlowDecision1",
"target": "WriteLine3",
"sourcePort": "True",
"targetPort": "In"
},
{
"source": "FlowDecision1",
"target": "WriteLine2",
"sourcePort": "False",
"targetPort": "In"
},
{
"source": "Start1",
"target": "WriteLine1",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "WriteLine2",
"target": "WriteLine1",
"sourcePort": "Done",
"targetPort": "In"
},
{
"source": "SetVariable1",
"target": "FlowDecision1",
"sourcePort": "Done",
"targetPort": "In"
}
]
}
}
@@ -0,0 +1,55 @@
{
"id": "3a793167cf6948c899d2f40c3c05cf0b",
"definitionId": "11e2b350dae8485498c16d1ce3843829",
"name": "Dummy workflow",
"createdAt": "2023-04-04T08:35:22.841043+00:00",
"version": 1,
"variables": [],
"inputs": [],
"outputs": [],
"outcomes": [],
"metadata": {},
"isLatest": true,
"isPublished": true,
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "Flowchart1",
"metadata": {},
"applicationProperties": {
"NotFoundConnectionsKey": []
},
"start": "WriteLine1",
"activities": [
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "Dummy Text"
},
"memoryReference": {
"id": "WriteLine1:input-1"
}
},
"id": "WriteLine1",
"type": "Elsa.WriteLine",
"version": 1,
"canStartWorkflow": false,
"runAsynchronously": false,
"customProperties": {},
"source": null,
"line": null,
"metadata": {
"designer": {
"position": {
"x": 2256,
"y": 2462
}
}
}
}
],
"connections": []
}
}
@@ -0,0 +1,35 @@
using Elsa.Testing.Shared;
using Elsa.Workflows.IncidentStrategies;
using Elsa.Workflows.IntegrationTests.Scenarios.Incidents.Statics;
using Elsa.Workflows.IntegrationTests.Scenarios.Incidents.Workflows;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.Incidents;
public class IncidentStrategyTests
{
private readonly IServiceProvider _services;
private readonly CapturingTextWriter _capturingTextWriter = new();
public IncidentStrategyTests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper)
.WithCapturingTextWriter(_capturingTextWriter)
.AddWorkflow<FaultyWorkflow>()
.Build();
}
[Theory(DisplayName = "Workflows with a Fault strategy do not continue after a fault")]
[InlineData(typeof(FaultStrategy), new[] { "Start", "Step 1a", "Step 2a" }, WorkflowSubStatus.Faulted)]
[InlineData(typeof(ContinueWithIncidentsStrategy), new[] { "Start", "Step 1a", "Step 2a", "Step 1b" }, WorkflowSubStatus.Suspended)]
public async Task Test0(Type incidentStrategyType, string[] expectedOutput, WorkflowSubStatus expectedSubStatus)
{
TestSettings.IncidentStrategyType = incidentStrategyType;
await _services.PopulateRegistriesAsync();
var workflowState = await _services.RunWorkflowUntilEndAsync<FaultyWorkflow>();
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(expectedOutput, lines);
Assert.Equal(expectedSubStatus, workflowState.SubStatus);
Assert.Equal(1, workflowState.Incidents.Count);
}
}
@@ -0,0 +1,8 @@
using Elsa.Workflows.IncidentStrategies;
namespace Elsa.Workflows.IntegrationTests.Scenarios.Incidents.Statics;
public static class TestSettings
{
public static Type IncidentStrategyType { get; set; } = typeof(FaultStrategy);
}
@@ -0,0 +1,51 @@
using Elsa.Workflows.Activities;
using Elsa.Workflows.Activities.Flowchart.Activities;
using Elsa.Workflows.Activities.Flowchart.Models;
using Elsa.Workflows.IntegrationTests.Scenarios.Incidents.Statics;
using Elsa.Workflows.Runtime.Activities;
namespace Elsa.Workflows.IntegrationTests.Scenarios.Incidents.Workflows;
public class FaultyWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder builder)
{
var start = new WriteLine("Start");
var step1A = new WriteLine("Step 1a");
var event1 = new Event("Event 1");
var step1B = new WriteLine("Step 1b");
var step2A = new WriteLine("Step 2a");
var event2 = new Event("Event 2");
var step2B = new WriteLine("Step 2b");
var fault = Fault.Create("Whoops!", "Test", "Test");
builder.WorkflowOptions.IncidentStrategyType = TestSettings.IncidentStrategyType;
builder.Root = new Flowchart
{
Activities =
{
start,
step1A,
event1,
step1B,
step2A,
event2,
step2B,
fault
},
Connections = new[]
{
new Connection(start, step1A),
new Connection(step1A, event1),
new Connection(event1, step1B),
new Connection(start, step2A),
new Connection(step2A, fault),
new Connection(fault, event2),
new Connection(event2, step2B),
}
};
}
}
@@ -0,0 +1,99 @@
using System.Text;
using Elsa.Expressions.Models;
using Elsa.Extensions;
using Elsa.JavaScript.Contracts;
using Elsa.Testing.Shared;
using Microsoft.Extensions.DependencyInjection;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.JavaScriptFunctions;
public class BytesAndStringEncodingTests
{
private readonly IJavaScriptEvaluator _evaluator;
private readonly ExpressionExecutionContext _expressionContext;
public BytesAndStringEncodingTests(ITestOutputHelper testOutputHelper)
{
var testOutputHelper1 = testOutputHelper ?? throw new ArgumentNullException(nameof(testOutputHelper));
var services = new TestApplicationBuilder(testOutputHelper1).Build();
_evaluator = services.GetRequiredService<IJavaScriptEvaluator>();
_expressionContext = new ExpressionExecutionContext(services, new MemoryRegister());
}
[Fact]
public async Task ByteArrayToString_ConvertsTo_String()
{
const string data = "Hello World!";
var bytes = Encoding.UTF8.GetBytes(data);
var script = "bytesToString(getData())";
_expressionContext.SetVariable("Data", bytes);
var result = (string)(await _evaluator.EvaluateAsync(script, typeof(string), _expressionContext))!;
Assert.Equal(data, result);
}
[Fact]
public async Task ByteArrayFromString_ConvertsTo_ByteArray()
{
const string data = "Hello World!";
var script = "bytesFromString(getData())";
_expressionContext.SetVariable("Data", data);
var result = (byte[])(await _evaluator.EvaluateAsync(script, typeof(byte[]), _expressionContext))!;
var bytes = Encoding.UTF8.GetBytes(data);
Assert.Equal(bytes, result);
}
[Fact]
public async Task ByteArrayToBase64_ConvertsTo_Base64()
{
const string data = "Hello World!";
var bytes = Encoding.UTF8.GetBytes(data);
var base64 = Convert.ToBase64String(bytes);
var script = "bytesToBase64(getData())";
_expressionContext.SetVariable("Data", bytes);
var result = (string)(await _evaluator.EvaluateAsync(script, typeof(string), _expressionContext))!;
Assert.Equal(base64, result);
}
[Fact]
public async Task ByteArrayFromBase64_ConvertsTo_ByteArray()
{
const string data = "Hello World!";
var bytes = Encoding.UTF8.GetBytes(data);
var base64 = Convert.ToBase64String(bytes);
var script = "bytesFromBase64(getData())";
_expressionContext.SetVariable("Data", base64);
var result = (byte[])(await _evaluator.EvaluateAsync(script, typeof(byte[]), _expressionContext))!;
Assert.Equal(bytes, result);
}
[Fact]
public async Task StringToBase64_ConvertsTo_Base64()
{
const string data = "Hello World!";
var bytes = Encoding.UTF8.GetBytes(data);
var base64 = Convert.ToBase64String(bytes);
var script = "stringToBase64(getData())";
_expressionContext.SetVariable("Data", data);
var result = (string)(await _evaluator.EvaluateAsync(script, typeof(string), _expressionContext))!;
Assert.Equal(base64, result);
}
[Fact]
public async Task StringFromBase64_ConvertsTo_String()
{
const string data = "Hello World!";
var bytes = Encoding.UTF8.GetBytes(data);
var base64 = Convert.ToBase64String(bytes);
var script = "stringFromBase64(getData())";
_expressionContext.SetVariable("Data", base64);
var result = (string)(await _evaluator.EvaluateAsync(script, typeof(string), _expressionContext))!;
Assert.Equal(data, result);
}
}
@@ -0,0 +1,120 @@
using System.Dynamic;
using Elsa.Expressions.Models;
using Elsa.Extensions;
using Elsa.JavaScript.Contracts;
using Elsa.Testing.Shared;
using Microsoft.Extensions.DependencyInjection;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.JavaScriptListsAndArrays;
public class Tests
{
private readonly IJavaScriptEvaluator _evaluator;
private readonly ExpressionExecutionContext _expressionContext;
public Tests(ITestOutputHelper testOutputHelper)
{
var testOutputHelper1 = testOutputHelper ?? throw new ArgumentNullException(nameof(testOutputHelper));
var services = new TestApplicationBuilder(testOutputHelper1).Build();
_evaluator = services.GetRequiredService<IJavaScriptEvaluator>();
_expressionContext = new ExpressionExecutionContext(services, new MemoryRegister());
}
[Fact(DisplayName = "Workflow inputs containing .NET lists on dynamic objects are converted to arrays for use in JavaScript.")]
public async Task Test1()
{
dynamic dynamicObject = new ExpandoObject();
dynamicObject.List = new List<string>
{
"a",
"b",
"c"
};
var script = "getObj().List.filter(x => x === 'b').length === 1";
_expressionContext.SetVariable("obj", (object)dynamicObject);
var result = await _evaluator.EvaluateAsync(script, typeof(bool), _expressionContext);
Assert.True((bool)result!);
}
[Fact(DisplayName = "Can access list properties as arrays")]
public async Task Test2()
{
var person = new ExpandoObject();
var magicNumbers = new[]
{
42, 43, 44
};
var order1 = new ExpandoObject();
order1.TryAdd("magicNumbers", magicNumbers);
person.TryAdd("orders", new[]
{
order1
});
person.TryAdd("name", "John");
person.TryAdd("age", 12);
var languages = new List<object>
{
"English",
"French"
};
person.TryAdd("languages", languages);
var obj = new ExpandoObject();
obj.TryAdd("persons", new List<object>
{
person
});
var name = await _evaluator.EvaluateAsync("o.persons.filter(x => x.age == 12)[0].name", typeof(string), _expressionContext, configureEngine: engine => engine.SetValue("o", obj));
var language = await _evaluator.EvaluateAsync("o.persons[0].languages.filter(x => x == 'English')[0]", typeof(string), _expressionContext, configureEngine: engine => engine.SetValue("o", obj));
var magicNumber = await _evaluator.EvaluateAsync("o.persons[0].orders[0].magicNumbers[1]", typeof(int), _expressionContext, configureEngine: engine => engine.SetValue("o", obj));
Assert.Equal("John", name);
Assert.Equal("English", language);
Assert.Equal(43, magicNumber);
}
[Theory(DisplayName = "Can sort array and list properties as mutable arrays")]
[MemberData(nameof(ArraySortEnumerableData))]
// See also:
// - https://github.com/sebastienros/jint/issues/1942
// - https://github.com/elsa-workflows/elsa-core/issues/5912
public async Task Test5(IEnumerable<double> collection)
{
dynamic dynamicObject = new ExpandoObject();
dynamicObject.Items = collection;
var script = """
const model = variables.Model;
model.Items.sort((a, b) => a - b);
return model;
""";
_expressionContext.SetVariable("Model", (object)dynamicObject);
dynamicObject = (ExpandoObject)(await _evaluator.EvaluateAsync(script, typeof(ExpandoObject), _expressionContext))!;
var items = ((object[])dynamicObject.Items).Cast<double>().ToArray();
Assert.Equal([2, 4, 8], items);
}
public static IEnumerable<object[]> ArraySortEnumerableData = new object[][]
{
[
new double[]
{
8, 4, 2
}
],
[
new List<double>
{
8,
4,
2
}
]
};
}
@@ -0,0 +1,35 @@
using System.Dynamic;
namespace Elsa.Workflows.IntegrationTests.Scenarios.JavaScriptNativeVariables;
public class Data
{
public static ExpandoObject CreateCustomerModel()
{
dynamic customer = new ExpandoObject();
customer.Name = "John Doe";
customer.Age = 42;
customer.Orders = new[]
{
new
{
Id = 1,
Product = "Apple",
Price = 10
},
new
{
Id = 3,
Product = "Orange",
Price = 30
},
new
{
Id = 2,
Product = "Banana",
Price = 20
}
};
return customer;
}
}
@@ -0,0 +1,38 @@
using Elsa.Extensions;
using Elsa.Testing.Shared;
using Microsoft.Extensions.DependencyInjection;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.JavaScriptNativeVariables;
public class Tests
{
private readonly IWorkflowRunner _workflowRunner;
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly IWorkflowBuilderFactory _workflowBuilderFactory;
private readonly IServiceProvider _services;
public Tests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper)
.WithCapturingTextWriter(_capturingTextWriter)
.ConfigureElsa(elsa => elsa.UseJavaScript())
.Build();
_workflowBuilderFactory = _services.GetRequiredService<IWorkflowBuilderFactory>();
_workflowRunner = _services.GetRequiredService<IWorkflowRunner>();
}
[Fact(DisplayName = "The JavaScript activity can access and modify native variables")]
public async Task Test1()
{
await _services.PopulateRegistriesAsync();
var workflow = await _workflowBuilderFactory.CreateBuilder().BuildWorkflowAsync<JavaScriptWorkflow>();
await _workflowRunner.RunAsync(workflow);
var line1 = _capturingTextWriter.Lines.ToList().ElementAt(0);
var line2 = _capturingTextWriter.Lines.ToList().ElementAt(1);
var line3 = _capturingTextWriter.Lines.ToList().ElementAt(2);
Assert.Equal("Jane Doe", line1);
Assert.Equal("Apple, Banana, Orange", line2);
Assert.Equal("jane.doe@acme.com", line3);
}
}
@@ -0,0 +1,33 @@
using Elsa.JavaScript.Activities;
using Elsa.JavaScript.Models;
using Elsa.Workflows.Activities;
namespace Elsa.Workflows.IntegrationTests.Scenarios.JavaScriptNativeVariables;
public class JavaScriptWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder workflow)
{
workflow.WithDefinitionId(Guid.NewGuid().ToString());
var customerVariable = workflow.WithVariable("customer", Data.CreateCustomerModel());
workflow.Root = new Sequence
{
Activities =
{
new RunJavaScript
{
Script = new("""
const customer = variables.customer;
customer.Name = 'Jane Doe';
customer.Orders.sort((a, b) => a.Product.localeCompare(b.Product));
variables.customer = {...customer, Email: 'jane.doe@acme.com'};
""")
},
new WriteLine(JavaScriptExpression.Create("variables.customer.Name")),
new WriteLine(JavaScriptExpression.Create("variables.customer.Orders.map(x => x.Product).join(', ')")),
new WriteLine(JavaScriptExpression.Create("variables.customer.Email"))
}
};
}
}
@@ -0,0 +1,44 @@
using Elsa.Testing.Shared;
using Elsa.Workflows.State;
using Microsoft.Extensions.DependencyInjection;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.JsonObjectSerialization;
/// <summary>
/// Tests for serializing and deserializing JSON objects containing reserved keywords such as $id.
/// </summary>
public class Tests
{
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly IServiceProvider _services;
private readonly IWorkflowStateSerializer _workflowStateSerializer;
public Tests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper).WithCapturingTextWriter(_capturingTextWriter).Build();
_workflowStateSerializer = _services.GetRequiredService<IWorkflowStateSerializer>();
}
[Fact(DisplayName = "User-objects containing $id don't break deserialization into ExpandoObject.")]
public async Task Test1()
{
// Populate registries.
await _services.PopulateRegistriesAsync();
// Import workflow.
var workflowFileName = "Scenarios/JsonObjectSerialization/Workflows/instance-serialization.json";
var workflowDefinition = await _services.ImportWorkflowDefinitionAsync(workflowFileName);
// Execute.
var workflowState = await _services.RunWorkflowUntilEndAsync(workflowDefinition.DefinitionId);
// Serialize workflow state.
var serializedWorkflowState = _workflowStateSerializer.Serialize(workflowState);
// Attempt to deserialize workflow state.
_workflowStateSerializer.Deserialize<WorkflowState>(serializedWorkflowState);
// If we reach this point, the test has passed. Otherwise, an exception would have been thrown.
}
}
@@ -0,0 +1,140 @@
{
"id": "b78e443339b5bf1e",
"definitionId": "861e51cdbe07931",
"name": "Instance Serialization",
"description": "This workflow stores a user-JSON object containing $id as a field, which should not affect the deserialization process form JSON back into ExpandoObject.",
"createdAt": "2023-11-23T15:18:12.805077+00:00",
"version": 13,
"toolVersion": "3.0.0.0",
"variables": [
{
"id": "d4f37df0c6781767",
"name": "Variable1",
"typeName": "Object",
"isArray": false,
"storageDriverTypeName": "Elsa.Workflows.Services.WorkflowStorageDriver, Elsa.Workflows.Core"
},
{
"id": "4e256dab27d33eac",
"name": "Variable2",
"typeName": "Object",
"isArray": false,
"storageDriverTypeName": "Elsa.Workflows.Services.WorkflowStorageDriver, Elsa.Workflows.Core"
}
],
"inputs": [],
"outputs": [],
"outcomes": [],
"customProperties": {},
"isReadonly": false,
"isLatest": true,
"isPublished": false,
"options": {
"autoUpdateConsumingWorkflows": false
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "35cdc2a3529d9b55",
"nodeId": "Workflow1:35cdc2a3529d9b55",
"metadata": {},
"customProperties": {
"source": "FlowchartJsonConverter.cs:47",
"notFoundConnections": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"activities": [
{
"variable": {
"id": "d4f37df0c6781767",
"name": "Variable1",
"typeName": "Object",
"storageDriverTypeName": "Elsa.Workflows.Services.WorkflowStorageDriver, Elsa.Workflows.Core"
},
"value": {
"typeName": "Object",
"expression": {
"type": "JavaScript",
"value": "return {\n \u0022inputSchema\u0022: {\n \u0022$schema\u0022: \u0022http://json-schema.org/draft-07/schema#\u0022,\n \u0022title\u0022: \u0022Inform front-office afd 2.0 input schema\u0022,\n \u0022description\u0022: \u0022Schema of the AFD 2.0 message that is sent to the front-office\u0022,\n \u0022$id\u0022: \u0022#/definitions/inform-front-office-input-afd\u0022,\n \u0022type\u0022: \u0022object\u0022\n }\n}"
},
"memoryReference": {
"id": "d4f32ee0ad659ba5:input-0"
}
},
"id": "d4f32ee0ad659ba5",
"nodeId": "Workflow1:35cdc2a3529d9b55:d4f32ee0ad659ba5",
"name": "SetVariable1",
"type": "Elsa.SetVariable",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -456.5988464355469,
"y": -104.93463134765625
},
"size": {
"width": 153.828125,
"height": 50
}
}
}
},
{
"variable": {
"id": "4e256dab27d33eac",
"name": "Variable2",
"typeName": "Object",
"storageDriverTypeName": "Elsa.Workflows.Services.WorkflowStorageDriver, Elsa.Workflows.Core"
},
"value": {
"typeName": "Object",
"expression": {
"type": "JavaScript",
"value": "return getVariable1()"
},
"memoryReference": {
"id": "31c60a181a1a66d8:input-0"
}
},
"id": "31c60a181a1a66d8",
"nodeId": "Workflow1:35cdc2a3529d9b55:31c60a181a1a66d8",
"name": "SetVariable2",
"type": "Elsa.SetVariable",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -210.69132232666016,
"y": -104.93463134765625
},
"size": {
"width": 153.828125,
"height": 50
}
}
}
}
],
"connections": [
{
"source": {
"activity": "d4f32ee0ad659ba5",
"port": "Done"
},
"target": {
"activity": "31c60a181a1a66d8",
"port": "In"
}
}
]
}
}
@@ -0,0 +1,20 @@
using System.Text.Json.Nodes;
using Elsa.Extensions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.JsonObjectToObjectRemainsJsonObject.Activities;
public class JsonObjectProducer : CodeActivity<JsonObject>
{
protected override void Execute(ActivityExecutionContext context)
{
var value = new JsonObject
{
["Foo"] = new JsonObject
{
["Bar"] = "Baz"
}
};
context.SetResult(value);
}
}
@@ -0,0 +1,15 @@
using Elsa.Extensions;
using Elsa.Workflows.Models;
namespace Elsa.Workflows.IntegrationTests.Scenarios.JsonObjectToObjectRemainsJsonObject.Activities;
public class ObjectProcessor : CodeActivity<object>
{
public Input<object> Value { get; set; } = default!;
protected override void Execute(ActivityExecutionContext context)
{
var value = Value.Get(context);
context.SetResult(value);
}
}
@@ -0,0 +1,28 @@
using Elsa.Testing.Shared;
using Microsoft.Extensions.DependencyInjection;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.JsonObjectToObjectRemainsJsonObject;
public class JsonObjectJintTests
{
private readonly IWorkflowRunner _workflowRunner;
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly IServiceProvider _services;
public JsonObjectJintTests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper).WithCapturingTextWriter(_capturingTextWriter).Build();
_services.GetRequiredService<IWorkflowBuilderFactory>();
_workflowRunner = _services.GetRequiredService<IWorkflowRunner>();
}
[Fact(DisplayName = "The produced JsonObject remains JsonObject and does not become JsonElement (which does not support index notation)")]
public async Task Test1()
{
await _services.PopulateRegistriesAsync();
await _workflowRunner.RunAsync<Workflows.TestWorkflow>();
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(new[] { "Baz" }, lines);
}
}
@@ -0,0 +1,32 @@
using System.Text.Json.Nodes;
using Elsa.Expressions.Models;
using Elsa.JavaScript.Models;
using Elsa.Workflows.Activities;
using Elsa.Workflows.IntegrationTests.Scenarios.JsonObjectToObjectRemainsJsonObject.Activities;
namespace Elsa.Workflows.IntegrationTests.Scenarios.JsonObjectToObjectRemainsJsonObject.Workflows;
public class TestWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder builder)
{
var item = builder.WithVariable<JsonObject>("item", default!);
builder.Root = new Sequence
{
Activities =
{
new JsonObjectProducer
{
Result = new(item)
},
new ObjectProcessor
{
Value = new(JavaScriptExpression.Create("getItem()"), new MemoryBlockReference()),
Result = new(item)
},
new WriteLine(JavaScriptExpression.Create("getItem()['Foo']['Bar']"))
}
};
}
}
@@ -0,0 +1,38 @@
using Elsa.Testing.Shared;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.ParentChildCompletion;
/// <summary>
/// Tests for mapping an activity's output directly to the workflow's output definition.
/// </summary>
public class Tests
{
private readonly IServiceProvider _services;
public Tests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper).Build();
}
[Fact(DisplayName = "Parent workflow invoking child workflow as activity completes successfully.")]
public async Task Test1()
{
// Populate registries.
await _services.PopulateRegistriesAsync();
// Import child workflow.
var childWorkflowFilename = "Scenarios/ParentChildCompletion/Workflows/child.json";
await _services.ImportWorkflowDefinitionAsync(childWorkflowFilename);
// Import parent workflow.
var parentWorkflowFilename = "Scenarios/ParentChildCompletion/Workflows/parent.json";
var parentWorkflowDefinition = await _services.ImportWorkflowDefinitionAsync(parentWorkflowFilename);
// Execute.
var workflowState = await _services.RunWorkflowUntilEndAsync(parentWorkflowDefinition.DefinitionId);
// Assert expected status
Assert.Equal(WorkflowStatus.Finished, workflowState.Status);
}
}
@@ -0,0 +1,303 @@
{
"id": "c8109a84c584c83c",
"definitionId": "3dcdbf22d29d6e60",
"name": "Subworkflow test",
"createdAt": "2023-11-10T13:03:21.734094+00:00",
"version": 4,
"toolVersion": "3.0.0.0",
"variables": [
{
"id": "c0dbe71ceb21ee4f",
"name": "Variable1",
"typeName": "Object",
"isArray": false,
"storageDriverTypeName": "Elsa.Workflows.Services.WorkflowStorageDriver, Elsa.Workflows.Core"
}
],
"inputs": [],
"outputs": [],
"outcomes": [
"Success",
"Failure"
],
"customProperties": {},
"isReadonly": false,
"isLatest": true,
"isPublished": true,
"options": {
"usableAsActivity": true,
"autoUpdateConsumingWorkflows": true
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "2492a1125f14bc2d",
"nodeId": "Workflow1:2492a1125f14bc2d",
"metadata": {},
"customProperties": {
"source": "FlowchartJsonConverter.cs:47",
"notFoundConnections": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"activities": [
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "test"
},
"memoryReference": {
"id": "a3625dd2e8405265:input-0"
}
},
"id": "a3625dd2e8405265",
"nodeId": "Workflow1:2492a1125f14bc2d:a3625dd2e8405265",
"name": "WriteLine1",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": true,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -174,
"y": 302
},
"size": {
"width": 139.296875,
"height": 50
}
}
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "1"
},
"memoryReference": {
"id": "31d29bf86b2b62cb:input-0"
}
},
"id": "31d29bf86b2b62cb",
"nodeId": "Workflow1:2492a1125f14bc2d:31d29bf86b2b62cb",
"name": "WriteLine3",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 132.6484375,
"y": 292
},
"size": {
"width": 139.296875,
"height": 50
}
}
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "11"
},
"memoryReference": {
"id": "57576570e00a4c70:input-0"
}
},
"id": "57576570e00a4c70",
"nodeId": "Workflow1:2492a1125f14bc2d:57576570e00a4c70",
"name": "WriteLine5",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 449.6484375,
"y": 280
},
"size": {
"width": 139.296875,
"height": 50
}
}
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "22"
},
"memoryReference": {
"id": "caa57f31b8d0e0d1:input-0"
}
},
"id": "caa57f31b8d0e0d1",
"nodeId": "Workflow1:2492a1125f14bc2d:caa57f31b8d0e0d1",
"name": "WriteLine4",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 449.6484375,
"y": 563
},
"size": {
"width": 139.296875,
"height": 50
}
}
}
},
{
"script": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "return {\u0022prop1\u0022:\u0022ceva\u0022}"
},
"memoryReference": {
"id": "fb20dbd8777282b2:input-0"
}
},
"possibleOutcomes": null,
"result": {
"typeName": "Object",
"memoryReference": {
"id": "c0dbe71ceb21ee4f"
}
},
"id": "fb20dbd8777282b2",
"nodeId": "Workflow1:2492a1125f14bc2d:fb20dbd8777282b2",
"name": "RunJavaScript1",
"type": "Elsa.RunJavaScript",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 114.453125,
"y": 563
},
"size": {
"width": 175.6875,
"height": 50
}
}
}
},
{
"outcomes": {
"typeName": "Object",
"expression": {
"type": "Literal",
"value": "Success"
},
"memoryReference": {
"id": "8654ab45535f4069:input-0"
}
},
"id": "8654ab45535f4069",
"nodeId": "Workflow1:2492a1125f14bc2d:8654ab45535f4069",
"name": "Complete1",
"type": "Elsa.Complete",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 738.7582397460938,
"y": 690.54443359375
},
"size": {
"width": 136.8125,
"height": 50
}
}
}
}
],
"connections": [
{
"source": {
"activity": "a3625dd2e8405265",
"port": "Done"
},
"target": {
"activity": "31d29bf86b2b62cb",
"port": "In"
}
},
{
"source": {
"activity": "31d29bf86b2b62cb",
"port": "Done"
},
"target": {
"activity": "57576570e00a4c70",
"port": "In"
}
},
{
"source": {
"activity": "fb20dbd8777282b2",
"port": "Done"
},
"target": {
"activity": "caa57f31b8d0e0d1",
"port": "In"
}
},
{
"source": {
"activity": "a3625dd2e8405265",
"port": "Done"
},
"target": {
"activity": "fb20dbd8777282b2",
"port": "In"
}
},
{
"source": {
"activity": "caa57f31b8d0e0d1",
"port": "Done"
},
"target": {
"activity": "8654ab45535f4069",
"port": "In"
}
}
]
}
}
@@ -0,0 +1,194 @@
{
"id": "34991d27edc12ae5",
"definitionId": "89d6fe82a11fbed6",
"name": "Mainworkflow test",
"createdAt": "2023-11-10T21:01:49.123204+00:00",
"version": 2,
"toolVersion": "3.0.0.0",
"variables": [],
"inputs": [],
"outputs": [],
"outcomes": [],
"customProperties": {
"Elsa:WorkflowContextProviderTypes": []
},
"isReadonly": false,
"isLatest": true,
"isPublished": true,
"options": {
"autoUpdateConsumingWorkflows": false
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "f9071ee83c88d765",
"nodeId": "Workflow1:f9071ee83c88d765",
"metadata": {},
"customProperties": {
"source": "FlowchartJsonConverter.cs:47",
"notFoundConnections": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"activities": [
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "Success"
},
"memoryReference": {
"id": "77069142b8b9da15:input-0"
}
},
"id": "77069142b8b9da15",
"nodeId": "Workflow1:f9071ee83c88d765:77069142b8b9da15",
"name": "WriteLine2",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 231.8203125,
"y": 200
},
"size": {
"width": 139.296875,
"height": 50
}
}
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "Failure"
},
"memoryReference": {
"id": "34e3dcda423f3c1c:input-0"
}
},
"id": "34e3dcda423f3c1c",
"nodeId": "Workflow1:f9071ee83c88d765:34e3dcda423f3c1c",
"name": "WriteLine3",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 231.8203125,
"y": 393
},
"size": {
"width": 139.296875,
"height": 50
}
}
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "Start"
},
"memoryReference": {
"id": "8b7bf9cd03c066fa:input-0"
}
},
"id": "8b7bf9cd03c066fa",
"nodeId": "Workflow1:f9071ee83c88d765:8b7bf9cd03c066fa",
"name": "WriteLine1",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -340,
"y": 309
},
"size": {
"width": 139.296875,
"height": 50
}
}
}
},
{
"workflowDefinitionId": "b8b45fd4dbffad5d",
"workflowDefinitionVersionId": "24dd11bc73a881d5",
"latestAvailablePublishedVersion": 7,
"latestAvailablePublishedVersionId": "24dd11bc73a881d5",
"id": "abcd6d3d391bfe10",
"nodeId": "Workflow1:f9071ee83c88d765:abcd6d3d391bfe10",
"name": "SubworkflowTest1",
"type": "SubworkflowTest",
"version": 7,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -54,
"y": 309
},
"size": {
"width": 157.09375,
"height": 50
}
}
}
}
],
"connections": [
{
"source": {
"activity": "8b7bf9cd03c066fa",
"port": "Done"
},
"target": {
"activity": "abcd6d3d391bfe10",
"port": "In"
}
},
{
"source": {
"activity": "abcd6d3d391bfe10",
"port": "Success"
},
"target": {
"activity": "77069142b8b9da15",
"port": "In"
}
},
{
"source": {
"activity": "abcd6d3d391bfe10",
"port": "Failure"
},
"target": {
"activity": "34e3dcda423f3c1c",
"port": "In"
}
}
]
}
}
@@ -0,0 +1,64 @@
using Elsa.Testing.Shared;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.ParentChildInputs;
/// <summary>
/// Tests for the flowchart completion feature using various workflow setups.
/// </summary>
public class Tests
{
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly IServiceProvider _services;
public Tests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper).WithCapturingTextWriter(_capturingTextWriter).Build();
}
[Fact(DisplayName = "Child activity receives workflow input from parent even if same name.")]
public async Task Test1()
{
// Populate registries.
await _services.PopulateRegistriesAsync();
// Import child workflow.
var childFileName = $"Scenarios/ParentChildInputs/Workflows/child.json";
await _services.ImportWorkflowDefinitionAsync(childFileName);
// Import parent workflow.
var parentFileName = $"Scenarios/ParentChildInputs/Workflows/parent1.json";
var workflowDefinition = await _services.ImportWorkflowDefinitionAsync(parentFileName);
// Execute.
var input = new Dictionary<string, object> { ["Input1"] = "Foo" };
await _services.RunWorkflowUntilEndAsync(workflowDefinition.DefinitionId, input);
// Assert expected output.
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(new[] { "Parent: Foo", "Child: Bar" }, lines);
}
[Fact(DisplayName = "Child activity receives input from parent event if same name and does not use global workflow input.")]
public async Task Test2()
{
// Populate registries.
await _services.PopulateRegistriesAsync();
// Import child workflow.
var childFileName = $"Scenarios/ParentChildInputs/Workflows/child.json";
await _services.ImportWorkflowDefinitionAsync(childFileName);
// Import parent workflow.
var parentFileName = $"Scenarios/ParentChildInputs/Workflows/parent2.json";
var workflowDefinition = await _services.ImportWorkflowDefinitionAsync(parentFileName);
// Execute.
var input = new Dictionary<string, object> { ["Input1"] = "Foo" };
await _services.RunWorkflowUntilEndAsync(workflowDefinition.DefinitionId, input);
// Assert expected output.
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(new[] { "Parent: Foo", "Child: Foo" }, lines);
}
}
@@ -0,0 +1,139 @@
{
"id": "228c0150ab7b4745b038b950be574935",
"definitionId": "25b097966de245818e9a5c0d04f3323e",
"name": "Child",
"createdAt": "2023-09-06T09:57:32.944622+00:00",
"version": 5,
"variables": [],
"inputs": [
{
"uiHint": "singleline",
"storageDriverType": "Elsa.Workflows.Services.WorkflowStorageDriver, Elsa.Workflows.Core",
"type": "Object",
"name": "Input1",
"displayName": "Input1",
"description": "",
"category": "",
"isArray": false
}
],
"outputs": [
{
"type": "Object",
"name": "Output1",
"displayName": "Output1",
"description": "",
"isArray": false
}
],
"outcomes": [],
"customProperties": {},
"isReadonly": false,
"isLatest": true,
"isPublished": true,
"options": {
"usableAsActivity": true,
"autoUpdateConsumingWorkflows": true
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "Flowchart1",
"metadata": {},
"customProperties": {
"source": "FlowchartJsonConverter.cs:45",
"NotFoundConnectionsKey": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"start": "WriteLine1",
"activities": [
{
"outputName": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "Output1"
},
"memoryReference": {
"id": "ca8473b5-83ec-4f75-a2f1-dfba71f349d1"
}
},
"outputValue": {
"typeName": "Object",
"expression": {
"type": "JavaScript",
"value": "return getInput1();"
},
"memoryReference": {
"id": "06c6243d-8a57-45e3-ae54-f209b95d2bb2"
}
},
"id": "SetOutput1",
"name": null,
"type": "Elsa.SetOutput",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 636,
"y": 250.01388549804688
},
"size": {
"width": 107.734375,
"height": 50
}
}
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "JavaScript",
"value": "\u0022Child: \u0022 \u002B getInput1();"
},
"memoryReference": {
"id": "3f726554-0fa1-4e54-b5e7-74b18807437b"
}
},
"id": "WriteLine1",
"name": null,
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 332.01385498046875,
"y": 222.01388549804688
},
"size": {
"width": 139.296875,
"height": 50
}
}
}
}
],
"connections": [
{
"source": {
"activity": "WriteLine1",
"port": "Done"
},
"target": {
"activity": "SetOutput1",
"port": "In"
}
}
]
}
}
@@ -0,0 +1,138 @@
{
"id": "e49f81715e29460187671ee298bbd0b2",
"definitionId": "6a4f5aeecbf94fc09dbba65363c5cb57",
"name": "Parent1",
"createdAt": "2023-09-06T11:38:10.701838+00:00",
"version": 8,
"variables": [],
"inputs": [
{
"uiHint": "singleline",
"storageDriverType": "Elsa.Workflows.Services.WorkflowStorageDriver, Elsa.Workflows.Core",
"type": "Object",
"name": "Input1",
"displayName": "Input1",
"description": "",
"category": "",
"isArray": false
}
],
"outputs": [
{
"type": "Object",
"name": "Output1",
"displayName": "Output1",
"description": "",
"isArray": false
}
],
"outcomes": [],
"customProperties": {},
"isReadonly": false,
"isLatest": true,
"isPublished": false,
"options": {
"autoUpdateConsumingWorkflows": false
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "Flowchart1",
"metadata": {},
"customProperties": {
"source": "FlowchartJsonConverter.cs:45",
"NotFoundConnectionsKey": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"start": "WriteLine1",
"activities": [
{
"text": {
"typeName": "String",
"expression": {
"type": "JavaScript",
"value": "\u0022Parent: \u0022 \u002B getInput1();"
},
"memoryReference": {
"id": "3070bee4-8309-44e3-a805-a9ec7fdd7ac2"
}
},
"id": "WriteLine1",
"name": null,
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 160,
"y": 280
},
"size": {
"width": 139.296875,
"height": 50
}
}
}
},
{
"workflowDefinitionId": "25b097966de245818e9a5c0d04f3323e",
"workflowDefinitionVersionId": "228c0150ab7b4745b038b950be574935",
"latestAvailablePublishedVersion": 5,
"latestAvailablePublishedVersionId": "228c0150ab7b4745b038b950be574935",
"id": "22jW7xiYM0K30H99EDWztQ",
"name": "Child1",
"type": "Child",
"version": 5,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 405.3984375,
"y": 204.0078125
},
"size": {
"width": 94.765625,
"height": 116.015625
}
}
},
"input1": {
"typeName": "Object",
"expression": {
"type": "JavaScript",
"value": "\u0060Bar\u0060"
},
"memoryReference": {
"id": "22jW7xiYM0K30H99EDWztQ:input-0"
}
},
"output1": {
"typeName": "Object",
"memoryReference": {
"id": "Output1"
}
}
}
],
"connections": [
{
"source": {
"activity": "WriteLine1",
"port": "Done"
},
"target": {
"activity": "22jW7xiYM0K30H99EDWztQ",
"port": "In"
}
}
]
}
}
@@ -0,0 +1,138 @@
{
"id": "c5aa339e124f4486b14dbfdc133a45d1",
"definitionId": "8ad20b5ff9ee4ff59b8dfcfb6d4e29a0",
"name": "Parent2",
"createdAt": "2023-09-06T11:38:30.217265+00:00",
"version": 1,
"variables": [],
"inputs": [
{
"uiHint": "singleline",
"storageDriverType": "Elsa.Workflows.Services.WorkflowStorageDriver, Elsa.Workflows.Core",
"type": "Object",
"name": "Input1",
"displayName": "Input1",
"description": "",
"category": "",
"isArray": false
}
],
"outputs": [
{
"type": "Object",
"name": "Output1",
"displayName": "Output1",
"description": "",
"isArray": false
}
],
"outcomes": [],
"customProperties": {},
"isReadonly": false,
"isLatest": true,
"isPublished": true,
"options": {
"autoUpdateConsumingWorkflows": false
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "Flowchart1",
"metadata": {},
"customProperties": {
"source": "FlowchartJsonConverter.cs:45",
"NotFoundConnectionsKey": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"start": "WriteLine1",
"activities": [
{
"text": {
"typeName": "String",
"expression": {
"type": "JavaScript",
"value": "\u0022Parent: \u0022 \u002B getInput1();"
},
"memoryReference": {
"id": "3070bee4-8309-44e3-a805-a9ec7fdd7ac2"
}
},
"id": "WriteLine1",
"name": null,
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 160,
"y": 280
},
"size": {
"width": 139.296875,
"height": 50
}
}
}
},
{
"workflowDefinitionId": "25b097966de245818e9a5c0d04f3323e",
"workflowDefinitionVersionId": "228c0150ab7b4745b038b950be574935",
"latestAvailablePublishedVersion": 5,
"latestAvailablePublishedVersionId": "228c0150ab7b4745b038b950be574935",
"id": "22jW7xiYM0K30H99EDWztQ",
"name": "Child1",
"type": "Child",
"version": 5,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 405.3984375,
"y": 204.0078125
},
"size": {
"width": 135.390625,
"height": 120
}
}
},
"input1": {
"typeName": "Object",
"expression": {
"type": "JavaScript",
"value": "getInput1()"
},
"memoryReference": {
"id": "22jW7xiYM0K30H99EDWztQ:input-0"
}
},
"output1": {
"typeName": "Object",
"memoryReference": {
"id": "Output1"
}
}
}
],
"connections": [
{
"source": {
"activity": "WriteLine1",
"port": "Done"
},
"target": {
"activity": "22jW7xiYM0K30H99EDWztQ",
"port": "In"
}
}
]
}
}
@@ -0,0 +1,84 @@
using Elsa.Testing.Shared;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.ParentChildOutputMapping;
/// <summary>
/// Tests for mapping an activity's output directly to the workflow's output definition.
/// </summary>
public class Tests
{
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly IServiceProvider _services;
public Tests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper).WithCapturingTextWriter(_capturingTextWriter).Build();
}
[Fact(DisplayName = "Parent workflow receives output from child workflow.")]
public async Task Test1()
{
// Populate registries.
await _services.PopulateRegistriesAsync();
// Import child workflow.
var sumFileName = "Scenarios/ParentChildOutputMapping/Workflows/sum.json";
await _services.ImportWorkflowDefinitionAsync(sumFileName);
// Import parent workflow.
var calculatorFileName = "Scenarios/ParentChildOutputMapping/Workflows/calculator.json";
var workflowDefinition = await _services.ImportWorkflowDefinitionAsync(calculatorFileName);
// Execute.
await _services.RunWorkflowUntilEndAsync(workflowDefinition.DefinitionId);
// Assert expected output.
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(new[] { "Result: 9" }, lines);
}
[Fact(DisplayName = "Multiple parent/child workflows receive output from child workflows even when using same output names.")]
public async Task Test2()
{
// Populate registries.
await _services.PopulateRegistriesAsync();
// Import workflows.
await _services.ImportWorkflowDefinitionAsync("Scenarios/ParentChildOutputMapping/Workflows/a.json");
await _services.ImportWorkflowDefinitionAsync("Scenarios/ParentChildOutputMapping/Workflows/b.json");
await _services.ImportWorkflowDefinitionAsync("Scenarios/ParentChildOutputMapping/Workflows/c.json");
// Import root workflow.
var workflowDefinition = await _services.ImportWorkflowDefinitionAsync("Scenarios/ParentChildOutputMapping/Workflows/d.json");
// Execute.
await _services.RunWorkflowUntilEndAsync(workflowDefinition.DefinitionId);
// Assert expected output.
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(new[] { "FooBar" }, lines);
}
[Fact(DisplayName = "Parent workflow receives output from child workflow when using SetOutput activity.")]
public async Task Test3()
{
// Populate registries.
await _services.PopulateRegistriesAsync();
// Import child workflow.
var producerFileName = "Scenarios/ParentChildOutputMapping/Workflows/producer.json";
await _services.ImportWorkflowDefinitionAsync(producerFileName);
// Import parent workflow.
var consumerFileName = "Scenarios/ParentChildOutputMapping/Workflows/consumer.json";
var workflowDefinition = await _services.ImportWorkflowDefinitionAsync(consumerFileName);
// Execute.
await _services.RunWorkflowUntilEndAsync(workflowDefinition.DefinitionId);
// Assert expected output.
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(new[] { "Foo" }, lines);
}
}
@@ -0,0 +1,89 @@
{
"id": "5d8015cea7b44c96",
"definitionId": "7fe314161d2d2ac6",
"name": "A",
"createdAt": "2023-11-15T13:55:38.86581+00:00",
"version": 1,
"toolVersion": "3.0.0.0",
"variables": [],
"inputs": [],
"outputs": [
{
"type": "Object",
"name": "Output1",
"displayName": "Output 1",
"category": "Primitives",
"isArray": false
}
],
"outcomes": [],
"customProperties": {
"Elsa:WorkflowContextProviderTypes": []
},
"isReadonly": false,
"isLatest": true,
"isPublished": true,
"options": {
"usableAsActivity": true,
"autoUpdateConsumingWorkflows": true
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "d84ccfca1b90bc0c",
"nodeId": "Workflow1:d84ccfca1b90bc0c",
"metadata": {},
"customProperties": {
"source": "FlowchartJsonConverter.cs:47",
"notFoundConnections": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"activities": [
{
"outputName": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "Output1"
},
"memoryReference": {
"id": "a6389a28e986c6ff:input-0"
}
},
"outputValue": {
"typeName": "Object",
"expression": {
"type": "Literal",
"value": "Foo"
},
"memoryReference": {
"id": "a6389a28e986c6ff:input-1"
}
},
"id": "a6389a28e986c6ff",
"nodeId": "Workflow1:d84ccfca1b90bc0c:a6389a28e986c6ff",
"name": "SetOutput1",
"type": "Elsa.SetOutput",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -60,
"y": 240
},
"size": {
"width": 107.734375,
"height": 50
}
}
}
}
],
"connections": []
}
}
@@ -0,0 +1,86 @@
{
"id": "d5221501eeb78037",
"definitionId": "8c751e0c53821439",
"name": "B",
"createdAt": "2023-11-15T13:59:18.773434+00:00",
"version": 1,
"toolVersion": "3.0.0.0",
"variables": [],
"inputs": [],
"outputs": [
{
"type": "Object",
"name": "Output1",
"displayName": "Output 1",
"category": "Primitives",
"isArray": false
}
],
"outcomes": [],
"customProperties": {
"Elsa:WorkflowContextProviderTypes": []
},
"isReadonly": false,
"isLatest": true,
"isPublished": true,
"options": {
"usableAsActivity": true,
"autoUpdateConsumingWorkflows": true
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "49a24a01a4c318de",
"nodeId": "Workflow1:49a24a01a4c318de",
"metadata": {},
"customProperties": {
"source": "FlowchartJsonConverter.cs:47",
"notFoundConnections": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"activities": [
{
"script": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "return \u0022Bar\u0022;"
},
"memoryReference": {
"id": "247da1e267d76f80:input-0"
}
},
"possibleOutcomes": null,
"result": {
"typeName": "Object",
"memoryReference": {
"id": "Output1"
}
},
"id": "247da1e267d76f80",
"nodeId": "Workflow1:49a24a01a4c318de:247da1e267d76f80",
"name": "RunCSharp1",
"type": "Elsa.RunCSharp",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -200,
"y": -140
},
"size": {
"width": 83.640625,
"height": 50
}
}
}
}
],
"connections": []
}
}
@@ -0,0 +1,130 @@
{
"id": "c4041d72854d317c",
"definitionId": "8472bcf9ca261e55",
"name": "C",
"createdAt": "2023-11-15T14:05:30.708042+00:00",
"version": 6,
"toolVersion": "3.0.0.0",
"variables": [],
"inputs": [],
"outputs": [
{
"type": "Object",
"name": "Output1",
"displayName": "Output 1",
"category": "Primitives",
"isArray": false
},
{
"type": "Object",
"name": "Output2",
"displayName": "Output 2",
"category": "Primitives",
"isArray": false
}
],
"outcomes": [],
"customProperties": {
"Elsa:WorkflowContextProviderTypes": []
},
"isReadonly": false,
"isLatest": true,
"isPublished": true,
"options": {
"usableAsActivity": true,
"autoUpdateConsumingWorkflows": true
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "6ee60c9988b58904",
"nodeId": "Workflow1:6ee60c9988b58904",
"metadata": {},
"customProperties": {
"source": "FlowchartJsonConverter.cs:47",
"notFoundConnections": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"activities": [
{
"workflowDefinitionId": "7fe314161d2d2ac6",
"workflowDefinitionVersionId": "5d8015cea7b44c96",
"latestAvailablePublishedVersion": 1,
"latestAvailablePublishedVersionId": "5d8015cea7b44c96",
"id": "67daca2a2fc729b6",
"nodeId": "Workflow1:6ee60c9988b58904:67daca2a2fc729b6",
"name": "A1",
"type": "A",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -311.5,
"y": -145
},
"size": {
"width": 41.59375,
"height": 50
}
}
},
"output1": {
"typeName": "Object",
"memoryReference": {
"id": "Output1"
}
}
},
{
"workflowDefinitionId": "8c751e0c53821439",
"workflowDefinitionVersionId": "d5221501eeb78037",
"latestAvailablePublishedVersion": 1,
"latestAvailablePublishedVersionId": "d5221501eeb78037",
"id": "d152d5815dcdea0d",
"nodeId": "Workflow1:6ee60c9988b58904:d152d5815dcdea0d",
"name": "B1",
"type": "B",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -194.5,
"y": -145
},
"size": {
"width": 41.125,
"height": 50
}
}
},
"output1": {
"typeName": "Object",
"memoryReference": {
"id": "Output2"
}
}
}
],
"connections": [
{
"source": {
"activity": "67daca2a2fc729b6",
"port": "Done"
},
"target": {
"activity": "d152d5815dcdea0d",
"port": "In"
}
}
]
}
}
@@ -0,0 +1,137 @@
{
"id": "Wv2qJngeBUy6nauIj3WZxg",
"definitionId": "g-yf4Gck40S_T1E5pW8OVA",
"name": "Calculator",
"createdAt": "2023-10-18T17:22:19.425264+00:00",
"version": 5,
"toolVersion": "3.0.0.0",
"variables": [
{
"id": "1a3c8e08fbf04b42b01f5df8e6296b74",
"name": "TheSum",
"typeName": "Int32",
"isArray": false,
"storageDriverTypeName": "Elsa.Workflows.Services.WorkflowStorageDriver, Elsa.Workflows.Core"
}
],
"inputs": [],
"outputs": [],
"outcomes": [],
"customProperties": {},
"isReadonly": false,
"isLatest": true,
"isPublished": true,
"options": {
"autoUpdateConsumingWorkflows": false
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "GGOfdS1e60-vuDvSskzt6A",
"metadata": {},
"customProperties": {
"source": "FlowchartJsonConverter.cs:46",
"notFoundConnections": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"activities": [
{
"workflowDefinitionId": "P4X-srRSDUeKpFHiDXMW-w",
"workflowDefinitionVersionId": "E02197RyVk6VyofGoO6YJQ",
"latestAvailablePublishedVersion": 3,
"latestAvailablePublishedVersionId": "E02197RyVk6VyofGoO6YJQ",
"id": "WDS8owJicUuwae0D5GPbZw",
"name": "Sum1",
"type": "Sum",
"version": 3,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -150.5,
"y": -173
},
"size": {
"width": 94.765625,
"height": 116.015625
}
}
},
"a": {
"typeName": "Int32",
"expression": {
"type": "Literal",
"value": "4"
},
"memoryReference": {
"id": "WDS8owJicUuwae0D5GPbZw:input-0"
}
},
"b": {
"typeName": "Int32",
"expression": {
"type": "Literal",
"value": "5"
},
"memoryReference": {
"id": "WDS8owJicUuwae0D5GPbZw:input-1"
}
},
"result": {
"typeName": "Int32",
"memoryReference": {
"id": "1a3c8e08fbf04b42b01f5df8e6296b74"
}
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "JavaScript",
"value": "\u0060Result: ${getTheSum()}\u0060"
},
"memoryReference": {
"id": "NDqbEDwcIUu7zJ0FDxbHdg:input-0"
}
},
"id": "NDqbEDwcIUu7zJ0FDxbHdg",
"name": "WriteLine1",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 80,
"y": -139.9921875
},
"size": {
"width": 139.296875,
"height": 50
}
}
}
}
],
"connections": [
{
"source": {
"activity": "WDS8owJicUuwae0D5GPbZw",
"port": "Done"
},
"target": {
"activity": "NDqbEDwcIUu7zJ0FDxbHdg",
"port": "In"
}
}
]
}
}
@@ -0,0 +1,125 @@
{
"id": "cae99c483081a2c",
"definitionId": "a7e44620e65e7184",
"name": "Consumer",
"createdAt": "2023-11-17T19:47:21.937582+00:00",
"version": 3,
"toolVersion": "3.0.0.0",
"variables": [
{
"id": "137ac38a229059f0",
"name": "Variable1",
"typeName": "Object",
"isArray": false,
"storageDriverTypeName": "Elsa.Workflows.Services.WorkflowStorageDriver, Elsa.Workflows.Core"
}
],
"inputs": [],
"outputs": [],
"outcomes": [],
"customProperties": {
"Elsa:WorkflowContextProviderTypes": []
},
"isReadonly": false,
"isLatest": true,
"isPublished": true,
"options": {
"usableAsActivity": false,
"autoUpdateConsumingWorkflows": true
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "cv7o3nnxp1dkxp1n",
"nodeId": "Workflow1:cv7o3nnxp1dkxp1n",
"metadata": {
"displayText": "Flowchart1"
},
"customProperties": {
"source": "FlowchartJsonConverter.cs:47",
"notFoundConnections": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"activities": [
{
"workflowDefinitionId": "69d6496437ff9d33",
"workflowDefinitionVersionId": "5c020d0052fb2860",
"latestAvailablePublishedVersion": 2,
"latestAvailablePublishedVersionId": "5c020d0052fb2860",
"id": "xcyl3fg7gg2uxcd4",
"nodeId": "Workflow1:cv7o3nnxp1dkxp1n:xcyl3fg7gg2uxcd4",
"name": "InternalPremiumCalculationGeneric1",
"type": "Producer",
"version": 2,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 2280,
"y": 2420
},
"size": {
"width": 318.140625,
"height": 50
}
}
},
"output1": {
"typeName": "Object",
"memoryReference": {
"id": "137ac38a229059f0"
}
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "CSharp",
"value": "return Variables.Variable1.ToString();"
},
"memoryReference": {
"id": "b3b9071594676f52:input-0"
}
},
"id": "b3b9071594676f52",
"nodeId": "Workflow1:cv7o3nnxp1dkxp1n:b3b9071594676f52",
"name": "WriteLine1",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 2695.5703125,
"y": 2420
},
"size": {
"width": 139.296875,
"height": 50
}
}
}
}
],
"connections": [
{
"source": {
"activity": "xcyl3fg7gg2uxcd4",
"port": "Done"
},
"target": {
"activity": "b3b9071594676f52",
"port": "In"
}
}
]
}
}
@@ -0,0 +1,135 @@
{
"id": "cbf12a4a3d1a52ef",
"definitionId": "133353946cd83e1d",
"name": "D",
"createdAt": "2023-11-15T14:07:04.052579+00:00",
"version": 1,
"toolVersion": "3.0.0.0",
"variables": [
{
"id": "f1106ece80fd17a8",
"name": "Variable1",
"typeName": "Object",
"isArray": false,
"storageDriverTypeName": "Elsa.Workflows.Services.WorkflowStorageDriver, Elsa.Workflows.Core"
},
{
"id": "3a8b25edc9bf109",
"name": "Variable2",
"typeName": "Object",
"isArray": false,
"storageDriverTypeName": "Elsa.Workflows.Services.WorkflowStorageDriver, Elsa.Workflows.Core"
}
],
"inputs": [],
"outputs": [],
"outcomes": [],
"customProperties": {
"Elsa:WorkflowContextProviderTypes": []
},
"isReadonly": false,
"isLatest": true,
"isPublished": true,
"options": {
"autoUpdateConsumingWorkflows": false
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "26838161a6f32e2e",
"nodeId": "Workflow1:26838161a6f32e2e",
"metadata": {},
"customProperties": {
"source": "FlowchartJsonConverter.cs:47",
"notFoundConnections": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"activities": [
{
"workflowDefinitionId": "8472bcf9ca261e55",
"workflowDefinitionVersionId": "c4041d72854d317c",
"latestAvailablePublishedVersion": 6,
"latestAvailablePublishedVersionId": "c4041d72854d317c",
"id": "db7bda6a28d8de82",
"nodeId": "Workflow1:26838161a6f32e2e:db7bda6a28d8de82",
"name": "C1",
"type": "C",
"version": 6,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -298.5,
"y": -168
},
"size": {
"width": 41.578125,
"height": 50
}
}
},
"output1": {
"typeName": "Object",
"memoryReference": {
"id": "f1106ece80fd17a8"
}
},
"output2": {
"typeName": "Object",
"memoryReference": {
"id": "3a8b25edc9bf109"
}
}
},
{
"text": {
"typeName": "String",
"expression": {
"type": "CSharp",
"value": "return $\u0022{Variables.Variable1}{Variables.Variable2}\u0022;"
},
"memoryReference": {
"id": "a815c4cf1e668419:input-0"
}
},
"id": "a815c4cf1e668419",
"nodeId": "Workflow1:26838161a6f32e2e:a815c4cf1e668419",
"name": "WriteLine1",
"type": "Elsa.WriteLine",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -139.5,
"y": -168
},
"size": {
"width": 139.296875,
"height": 50
}
}
}
}
],
"connections": [
{
"source": {
"activity": "db7bda6a28d8de82",
"port": "Done"
},
"target": {
"activity": "a815c4cf1e668419",
"port": "In"
}
}
]
}
}
@@ -0,0 +1,92 @@
{
"id": "5c020d0052fb2860",
"definitionId": "69d6496437ff9d33",
"name": "Producer",
"createdAt": "2023-11-17T19:45:52.798011+00:00",
"version": 2,
"toolVersion": "3.0.0.0",
"variables": [],
"inputs": [],
"outputs": [
{
"type": "Object",
"name": "Output1",
"displayName": "Output 1",
"category": "Primitives",
"isArray": false
}
],
"outcomes": [],
"customProperties": {
"Elsa:WorkflowContextProviderTypes": []
},
"isReadonly": false,
"isLatest": true,
"isPublished": true,
"options": {
"usableAsActivity": true,
"autoUpdateConsumingWorkflows": true
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "nn98bbdkmvkbkuda",
"nodeId": "Workflow1:nn98bbdkmvkbkuda",
"metadata": {
"displayText": "Flowchart1"
},
"customProperties": {
"source": "FlowchartJsonConverter.cs:47",
"notFoundConnections": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"activities": [
{
"outputName": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "Output1"
},
"memoryReference": {
"id": "825749ed-b1ad-48f0-aa51-f739c71420a4"
}
},
"outputValue": {
"typeName": "Object",
"expression": {
"type": "Literal",
"value": "Foo"
},
"memoryReference": {
"id": "427d771a-a3e2-4a1c-bb40-c1f4ccf3d0c7"
}
},
"id": "4c9j38qta2bmc096",
"nodeId": "Workflow1:nn98bbdkmvkbkuda:4c9j38qta2bmc096",
"name": "SetOutput1",
"type": "Elsa.SetOutput",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 400,
"y": 40
},
"size": {
"width": 175.578125,
"height": 50
}
},
"displayText": ""
}
}
],
"connections": []
}
}
@@ -0,0 +1,102 @@
{
"id": "E02197RyVk6VyofGoO6YJQ",
"definitionId": "P4X-srRSDUeKpFHiDXMW-w",
"name": "Sum",
"createdAt": "2023-10-18T16:37:20.670222+00:00",
"version": 3,
"toolVersion": "3.0.0.0",
"variables": [],
"inputs": [
{
"uiHint": "singleline",
"storageDriverType": "Elsa.Workflows.Services.WorkflowStorageDriver, Elsa.Workflows.Core",
"type": "Int32",
"name": "A",
"displayName": "A",
"category": "Primitives",
"isArray": false
},
{
"uiHint": "singleline",
"storageDriverType": "Elsa.Workflows.Services.WorkflowStorageDriver, Elsa.Workflows.Core",
"type": "Int32",
"name": "B",
"displayName": "B",
"category": "Primitives",
"isArray": false
}
],
"outputs": [
{
"type": "Int32",
"name": "Result",
"displayName": "Result",
"category": "Primitives",
"isArray": false
}
],
"outcomes": [],
"customProperties": {},
"isReadonly": false,
"isLatest": true,
"isPublished": true,
"options": {
"usableAsActivity": true,
"autoUpdateConsumingWorkflows": true,
"activityCategory": "Custom"
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "4FUOkS0zNUGe8JyVY3Sqmw",
"metadata": {},
"customProperties": {
"source": "FlowchartJsonConverter.cs:46",
"notFoundConnections": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"activities": [
{
"possibleOutcomes": null,
"script": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "getA() \u002B getB()"
},
"memoryReference": {
"id": "weO38K8Dfk-cSK8KVIiQMg:input-1"
}
},
"result": {
"typeName": "Object",
"memoryReference": {
"id": "Result"
}
},
"id": "weO38K8Dfk-cSK8KVIiQMg",
"name": "RunJavaScript1",
"type": "Elsa.RunJavaScript",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -240,
"y": 300
},
"size": {
"width": 175.6875,
"height": 50
}
}
}
}
],
"connections": []
}
}
@@ -0,0 +1,27 @@
using Elsa.Workflows.Attributes;
using Elsa.Workflows.Models;
namespace Elsa.Workflows.IntegrationTests.Scenarios.RunAsynchronousActivityOutput.Activities;
[Activity("Elsa.Test", Kind = ActivityKind.Task)]
internal class SampleActivity : CodeActivity
{
public SampleActivity()
{
RunAsynchronously = true;
}
public Input<int>? Number1 { get; set; } = null;
public Input<int>? Number2 { get; set; } = null;
public Output<int>? Sum { get; set; } = null;
public Output<int>? Product { get; set; } = null;
protected override void Execute(ActivityExecutionContext context)
{
var number1 = context.Get(Number1);
var number2 = context.Get(Number2);
context.Set(Sum, number1 + number2);
context.Set(Product, number1 * number2);
}
}
@@ -0,0 +1,155 @@
using Elsa.Extensions;
using Elsa.Testing.Shared;
using Elsa.Workflows.Activities;
using Elsa.Workflows.IntegrationTests.Scenarios.RunAsynchronousActivityOutput.Activities;
using Elsa.Workflows.Memory;
using Elsa.Workflows.Runtime.Distributed;
using Elsa.Workflows.Runtime.Stores;
using Microsoft.Extensions.DependencyInjection;
namespace Elsa.Workflows.IntegrationTests.Scenarios.RunAsynchronousActivityOutput;
public class Tests
{
[Theory(DisplayName = "Activity outputs captured in activity execution record")]
[InlineData(true)]
[InlineData(false)]
public async Task ActivityOutputCaptureTest(bool runAsynchronously)
{
// Arrange
var workflow = new TestWorkflow(workflowBuilder =>
{
var variable1 = new Variable<int>();
workflowBuilder.Root = new Sequence
{
Variables =
{
variable1
},
Activities =
{
new SampleActivity
{
Id = "SampleActivity1",
RunAsynchronously = runAsynchronously,
Number1 = new(4),
Number2 = new(8),
Sum = new(variable1),
Product = null
}
}
};
});
var activityExecutionStore = new MemoryActivityExecutionStore(new());
// Act
var workflowFinishedRecord = await workflow.DispatchWorkflowAndRunToCompletion(
configureElsa: elsa =>
{
elsa.UseWorkflowRuntime(workflowRuntime =>
{
workflowRuntime.ActivityExecutionLogStore = sp => activityExecutionStore;
});
}
);
// Assert
Assert.NotNull(workflowFinishedRecord);
Assert.Equal(WorkflowStatus.Finished, workflowFinishedRecord.WorkflowState.Status);
Assert.Equal(WorkflowSubStatus.Finished, workflowFinishedRecord.WorkflowState.SubStatus);
var activityExecutionRecord = await activityExecutionStore.FindAsync(new()
{
ActivityId = "SampleActivity1"
});
Assert.NotNull(activityExecutionRecord?.Outputs);
Assert.Equal(2, activityExecutionRecord.Outputs!.Count);
Assert.Equal(12, activityExecutionRecord.Outputs!.GetValue<int>("Sum"));
Assert.Equal(32, activityExecutionRecord.Outputs!.GetValue<int>("Product"));
var activityOutputRegister = workflowFinishedRecord.WorkflowExecutionContext.GetActivityOutputRegister();
Assert.Equal(12, activityOutputRegister.FindOutputByActivityId("SampleActivity1", "Sum"));
Assert.Equal(32, activityOutputRegister.FindOutputByActivityId("SampleActivity1", "Product"));
}
[Theory(DisplayName = "Activity outputs captured in activity execution record")]
[InlineData(true)]
[InlineData(false)]
public async Task ActivityOutputCaptureParallelTest(bool runAsynchronously)
{
// Arrange
var workflow = new TestWorkflow(workflowBuilder =>
{
var variable1 = new Variable<int>();
var variable2 = new Variable<int>();
workflowBuilder.Root = new Elsa.Workflows.Activities.Parallel
{
Variables =
{
variable1,
variable2,
},
Activities =
{
new SampleActivity
{
Id = "SampleActivity1",
RunAsynchronously = runAsynchronously,
Number1 = new(4),
Number2 = new(8),
Sum = new(variable1),
},
new SampleActivity
{
Id = "SampleActivity2",
RunAsynchronously = runAsynchronously,
Number1 = new(2),
Number2 = new(7),
Product = new(variable2),
}
}
};
});
var activityExecutionStore = new MemoryActivityExecutionStore(new());
// Act
var workflowFinishedRecord = await workflow.DispatchWorkflowAndRunToCompletion(
configureServices: services =>
{
services.AddScoped<DistributedWorkflowRuntime>();
},
configureElsa: elsa =>
{
elsa.UseWorkflowRuntime(workflowRuntime =>
{
workflowRuntime.ActivityExecutionLogStore = sp => activityExecutionStore;
workflowRuntime.WorkflowRuntime = sp => sp.GetRequiredService<DistributedWorkflowRuntime>();
});
});
// Assert
Assert.NotNull(workflowFinishedRecord);
Assert.Equal(WorkflowStatus.Finished, workflowFinishedRecord.WorkflowState.Status);
Assert.Equal(WorkflowSubStatus.Finished, workflowFinishedRecord.WorkflowState.SubStatus);
var activityExecutionRecord1 = await activityExecutionStore.FindAsync(new()
{
ActivityId = "SampleActivity1"
});
Assert.NotNull(activityExecutionRecord1?.Outputs);
Assert.Equal(2, activityExecutionRecord1.Outputs!.Count);
Assert.Equal(12, activityExecutionRecord1.Outputs!.GetValue<int>("Sum"));
Assert.Equal(32, activityExecutionRecord1.Outputs!.GetValue<int>("Product"));
var activityExecutionRecord2 = await activityExecutionStore.FindAsync(new()
{
ActivityId = "SampleActivity2"
});
Assert.NotNull(activityExecutionRecord2?.Outputs);
Assert.Equal(2, activityExecutionRecord2.Outputs!.Count);
Assert.Equal(9, activityExecutionRecord2.Outputs!.GetValue<int>("Sum"));
Assert.Equal(14, activityExecutionRecord2.Outputs!.GetValue<int>("Product"));
}
}
@@ -0,0 +1,31 @@
using Elsa.Testing.Shared;
using Elsa.Workflows.Management;
using Microsoft.Extensions.DependencyInjection;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.Serialization;
public class Tests
{
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly IServiceProvider _services;
private readonly IWorkflowDefinitionPublisher _publisher;
private readonly IActivitySerializer _serializer;
public Tests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper).WithCapturingTextWriter(_capturingTextWriter).Build();
_services.GetRequiredService<IWorkflowBuilderFactory>();
_publisher = _services.GetRequiredService<IWorkflowDefinitionPublisher>();
_serializer = _services.GetRequiredService<IActivitySerializer>();
}
[Fact(DisplayName = "Can serialize newly created workflow definition")]
public async Task Test1()
{
await _services.PopulateRegistriesAsync();
var workflowDefinition = _publisher.New();
var root = _serializer.Deserialize(workflowDefinition.StringData);
Assert.NotNull(root);
}
}
@@ -0,0 +1,50 @@
using Elsa.Testing.Shared;
using Microsoft.Extensions.DependencyInjection;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.SetGetVariables;
public class Tests
{
private readonly IWorkflowRunner _workflowRunner;
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly IServiceProvider _services;
public Tests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper).WithCapturingTextWriter(_capturingTextWriter).Build();
_services.GetRequiredService<IWorkflowBuilderFactory>();
_workflowRunner = _services.GetRequiredService<IWorkflowRunner>();
}
[Fact(DisplayName = "Workflow can set variable")]
public async Task Test1()
{
await _services.PopulateRegistriesAsync();
await _workflowRunner.RunAsync<SetGetVariableWorkflow>();
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(new[] { "Line 5" }, lines);
}
[Fact(DisplayName = "Workflow can reference variables set in previous activities")]
public async Task Test2()
{
await _services.PopulateRegistriesAsync();
await _workflowRunner.RunAsync<SetGetVariablesWorkflow>();
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(new[] { "Variable 2: The value of variable 1" }, lines);
}
[Fact(DisplayName = "Workflow can set and get named variables")]
public async Task Test3()
{
await _services.PopulateRegistriesAsync();
await _workflowRunner.RunAsync<SetGetNamedVariableWorkflow>();
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(new[]
{
"Foo = Bar",
"Foo = Baz"
}, lines);
}
}
@@ -0,0 +1,74 @@
using Elsa.Extensions;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Memory;
namespace Elsa.Workflows.IntegrationTests.Scenarios.SetGetVariables;
class SetGetVariableWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder workflow)
{
var variable1 = new Variable<string>("Variable1", "");
workflow.Root = new Sequence
{
Variables =
{
variable1
},
Activities =
{
new SetVariable<string>(variable1, "Line 5"),
new WriteLine(variable1)
}
};
}
}
class SetGetVariablesWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder workflow)
{
var variable1 = new Variable<string>("Variable1", "");
var variable2 = new Variable<string>("Variable2", "");
workflow.Root = new Sequence
{
Variables = { variable1, variable2 },
Activities =
{
new SetVariable
{
Variable = variable1,
Value = new("The value of variable 1")
},
new SetVariable
{
Variable = variable2,
Value = new(variable1)
},
new WriteLine(context => $"Variable 2: {variable2.Get(context)}")
}
};
}
}
class SetGetNamedVariableWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder workflow)
{
workflow.Root = new Sequence
{
Variables = { new Variable<string>("Foo", "Bar") },
Activities =
{
new WriteLine(context => $"Foo = {context.GetVariable<string>("Foo")}"),
Inline.From(context => context.SetVariable("Foo", "Baz")),
new WriteLine(context => $"Foo = {context.GetVariable<string>("Foo")}"),
}
};
}
}
@@ -0,0 +1,11 @@
using Elsa.Extensions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.SetGetVariablesFromActivities.Activities;
public class CreateVariableActivity : CodeActivity
{
protected override void Execute(ActivityExecutionContext context)
{
context.SetVariable("Foo", "Bar");
}
}
@@ -0,0 +1,12 @@
using Elsa.Extensions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.SetGetVariablesFromActivities.Activities;
public class ReadVariableActivity : CodeActivity<string>
{
protected override void Execute(ActivityExecutionContext context)
{
var foo = context.GetVariable<string>("Foo");
Result.Set(context, foo);
}
}
@@ -0,0 +1,29 @@
using Elsa.Testing.Shared;
using Elsa.Workflows.IntegrationTests.Scenarios.SetGetVariablesFromActivities.Workflows;
using Microsoft.Extensions.DependencyInjection;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.SetGetVariablesFromActivities;
public class Tests
{
private readonly IWorkflowRunner _workflowRunner;
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly IServiceProvider _services;
public Tests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper).WithCapturingTextWriter(_capturingTextWriter).Build();
_services.GetRequiredService<IWorkflowBuilderFactory>();
_workflowRunner = _services.GetRequiredService<IWorkflowRunner>();
}
[Fact(DisplayName = "Activities can set and get variables internally")]
public async Task Test1()
{
await _services.PopulateRegistriesAsync();
await _workflowRunner.RunAsync<SampleWorkflow>();
var lines = _capturingTextWriter.Lines.ToList();
Assert.Equal(new[] { "Bar" }, lines);
}
}
@@ -0,0 +1,31 @@
using Elsa.Workflows.Activities;
using Elsa.Workflows.IntegrationTests.Scenarios.SetGetVariablesFromActivities.Activities;
using Elsa.Workflows.Memory;
namespace Elsa.Workflows.IntegrationTests.Scenarios.SetGetVariablesFromActivities.Workflows;
class SampleWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder workflow)
{
var variable1 = new Variable<string>("Variable1", "");
workflow.Root = new Sequence
{
Variables =
{
variable1
},
Activities =
{
new CreateVariableActivity(),
new ReadVariableActivity
{
Result = new(variable1)
},
new WriteLine(variable1)
}
};
}
}
@@ -0,0 +1,78 @@
using Elsa.Common.Models;
using Elsa.Mediator.HostedServices;
using Elsa.Mediator.Options;
using Elsa.Testing.Shared;
using Elsa.Workflows.IntegrationTests.Scenarios.WorkflowCancellation.Workflows;
using Elsa.Workflows.Models;
using Elsa.Workflows.Runtime;
using Elsa.Workflows.Runtime.Messages;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Xunit.Abstractions;
namespace Elsa.Workflows.IntegrationTests.Scenarios.WorkflowCancellation;
/// <summary>
/// Represents a class containing unit tests for the DefaultRuntime class.
/// </summary>
public class DefaultRuntimeTests
{
private readonly IServiceProvider _services;
private readonly CapturingTextWriter _capturingTextWriter = new();
private readonly IWorkflowRuntime _workflowRuntime;
/// <summary>
/// Initializes a new instance of the <see cref="DefaultRuntimeTests"/> class.
/// </summary>
public DefaultRuntimeTests(ITestOutputHelper testOutputHelper)
{
_services = new TestApplicationBuilder(testOutputHelper)
.WithCapturingTextWriter(_capturingTextWriter)
.AddWorkflow<BulkSuspendedWorkflow>()
.AddWorkflow<ResumeDispatchWorkflow>()
.AddWorkflow<SimpleChildWorkflow>()
.AddWorkflow<SimpleSuspendedWorkflow>()
.ConfigureServices(services =>
{
services
.AddSingleton(sp =>
{
var options = sp.GetRequiredService<IOptions<MediatorOptions>>().Value;
return ActivatorUtilities.CreateInstance<BackgroundCommandSenderHostedService>(sp, options.CommandWorkerCount);
})
.AddSingleton(sp =>
{
var options = sp.GetRequiredService<IOptions<MediatorOptions>>().Value;
return ActivatorUtilities.CreateInstance<BackgroundEventPublisherHostedService>(sp, options.NotificationWorkerCount);
})
;
})
.Build();
_workflowRuntime = _services.GetRequiredService<IWorkflowRuntime>();
}
[Fact(DisplayName = "Cancelling a suspended workflow")]
public async Task SuspendedCancelTest()
{
await _services.PopulateRegistriesAsync();
const string workflowDefinitionId = nameof(SimpleSuspendedWorkflow);
var workflowClient = await _workflowRuntime.CreateClientAsync();
await workflowClient.CreateInstanceAsync(new()
{
WorkflowDefinitionHandle = WorkflowDefinitionHandle.ByDefinitionId(workflowDefinitionId, VersionOptions.Published)
});
var runWorkflowInstanceResponse = await workflowClient.RunInstanceAsync(RunWorkflowInstanceRequest.Empty);
Assert.Equal(WorkflowStatus.Running, runWorkflowInstanceResponse.Status);
Assert.Equal(WorkflowSubStatus.Suspended, runWorkflowInstanceResponse.SubStatus);
await workflowClient.CancelAsync();
var lastWorkflowState = await workflowClient.ExportStateAsync();
Assert.Equal(WorkflowStatus.Finished, lastWorkflowState!.Status);
Assert.Equal(WorkflowSubStatus.Cancelled, lastWorkflowState.SubStatus);
Assert.Empty(_capturingTextWriter.Lines);
}
}
@@ -0,0 +1,27 @@
using Elsa.Scheduling.Activities;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Runtime.Activities;
namespace Elsa.Workflows.IntegrationTests.Scenarios.WorkflowCancellation.Workflows;
public class BulkSuspendedWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder builder)
{
object[] items = Enumerable.Range(0, 1500).Select(x => (object)x).ToArray();
builder.Root = new Sequence
{
Activities =
{
new Start(),
new Delay(TimeSpan.FromSeconds(10)),
new BulkDispatchWorkflows
{
WorkflowDefinitionId = new(nameof(SimpleChildWorkflow)),
Items = new(items)
}
},
};
}
}

Some files were not shown because too many files have changed in this diff Show More