From 21dbb27c83dc4c0c2f8a2ec6737dc0229f3c1f93 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 25 Apr 2026 12:37:22 +0000 Subject: [PATCH 1/2] Initial plan From fbfc545cd242933b237e36464f03bf55ce5bad76 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 25 Apr 2026 12:46:40 +0000 Subject: [PATCH 2/2] Expose dispatch workflow instance id result Agent-Logs-Url: https://github.com/elsa-workflows/elsa-core/sessions/0bbd5643-3bbf-473d-b29e-c538763b6183 Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com> --- .../Activities/DispatchWorkflow.cs | 3 +- .../Composition/DispatchWorkflowTests.cs | 106 ++++++++++++++++++ 2 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 test/unit/Elsa.Activities.UnitTests/Composition/DispatchWorkflowTests.cs diff --git a/src/modules/Elsa.Workflows.Runtime/Activities/DispatchWorkflow.cs b/src/modules/Elsa.Workflows.Runtime/Activities/DispatchWorkflow.cs index 1489ef1209..cea78701f7 100644 --- a/src/modules/Elsa.Workflows.Runtime/Activities/DispatchWorkflow.cs +++ b/src/modules/Elsa.Workflows.Runtime/Activities/DispatchWorkflow.cs @@ -94,6 +94,7 @@ protected override async ValueTask ExecuteAsync(ActivityExecutionContext context else { // Otherwise, we can complete immediately. + context.SetResult(instanceId); await context.CompleteActivityAsync(); } } @@ -155,4 +156,4 @@ private async ValueTask OnChildWorkflowCompletedAsync(ActivityExecutionContext c context.Set(Result, input); await context.CompleteActivityAsync(); } -} \ No newline at end of file +} diff --git a/test/unit/Elsa.Activities.UnitTests/Composition/DispatchWorkflowTests.cs b/test/unit/Elsa.Activities.UnitTests/Composition/DispatchWorkflowTests.cs new file mode 100644 index 0000000000..5e4734c35f --- /dev/null +++ b/test/unit/Elsa.Activities.UnitTests/Composition/DispatchWorkflowTests.cs @@ -0,0 +1,106 @@ +using Elsa.Common.Models; +using Elsa.Extensions; +using Elsa.Testing.Shared; +using Elsa.Workflows; +using Elsa.Workflows.Activities; +using Elsa.Workflows.Management; +using Elsa.Workflows.Models; +using Elsa.Workflows.Runtime; +using Elsa.Workflows.Runtime.Activities; +using Elsa.Workflows.Runtime.Requests; +using Elsa.Workflows.Runtime.Responses; +using Microsoft.Extensions.DependencyInjection; +using NSubstitute; + +namespace Elsa.Activities.UnitTests.Composition; + +public class DispatchWorkflowTests +{ + private const string DefaultWorkflowDefinitionId = "test-workflow-def"; + private const string DefaultGeneratedId = "generated-child-id"; + + [Fact] + public async Task Should_Set_Result_To_Dispatched_Workflow_Instance_Id_When_Not_Waiting() + { + var dispatchWorkflow = new DispatchWorkflow + { + WorkflowDefinitionId = new(DefaultWorkflowDefinitionId), + WaitForCompletion = new(false) + }; + + var (context, _) = await ExecuteAsync(dispatchWorkflow); + + var result = context.GetActivityOutput(() => dispatchWorkflow.Result); + Assert.Equal(DefaultGeneratedId, result); + } + + [Fact] + public async Task Should_Dispatch_Workflow_With_Generated_Instance_Id() + { + var dispatchWorkflow = new DispatchWorkflow + { + WorkflowDefinitionId = new(DefaultWorkflowDefinitionId), + WaitForCompletion = new(false) + }; + + var (_, workflowDispatcher) = await ExecuteAsync(dispatchWorkflow); + + await workflowDispatcher.Received(1).DispatchAsync( + Arg.Is(request => request.InstanceId == DefaultGeneratedId), + Arg.Any(), + Arg.Any()); + } + + private static WorkflowGraph CreateMockWorkflowGraph() + { + var writeLine = new WriteLine("Test") { Id = "test-activity" }; + var workflow = Workflow.FromActivity(writeLine); + workflow.Id = "test-workflow"; + var rootNode = new ActivityNode(writeLine, "Done"); + return new(workflow, rootNode, [rootNode]); + } + + private static IWorkflowDefinitionService CreateWorkflowDefinitionService(string workflowDefinitionId, WorkflowGraph workflowGraph) + { + var service = Substitute.For(); + service + .FindWorkflowGraphAsync(workflowDefinitionId, Arg.Any(), Arg.Any()) + .Returns(workflowGraph); + return service; + } + + private static IIdentityGenerator CreateIdentityGenerator(string generatedId) + { + var generator = Substitute.For(); + generator.GenerateId().Returns(generatedId); + return generator; + } + + private static IWorkflowDispatcher CreateWorkflowDispatcher() + { + var dispatcher = Substitute.For(); + dispatcher + .DispatchAsync(Arg.Any(), Arg.Any(), Arg.Any()) + .Returns(DispatchWorkflowResponse.Success()); + return dispatcher; + } + + private static async Task<(ActivityExecutionContext Context, IWorkflowDispatcher WorkflowDispatcher)> ExecuteAsync(DispatchWorkflow dispatchWorkflow) + { + var workflowGraph = CreateMockWorkflowGraph(); + var workflowDefinitionService = CreateWorkflowDefinitionService(DefaultWorkflowDefinitionId, workflowGraph); + var identityGenerator = CreateIdentityGenerator(DefaultGeneratedId); + var workflowDispatcher = CreateWorkflowDispatcher(); + + var context = await new ActivityTestFixture(dispatchWorkflow) + .ConfigureServices(services => + { + services.AddSingleton(workflowDefinitionService); + services.AddSingleton(identityGenerator); + services.AddSingleton(workflowDispatcher); + }) + .ExecuteAsync(); + + return (context, workflowDispatcher); + } +}