From 75cb3a3de22761201ee01ff951efbcc2cd575d7b Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Thu, 5 Dec 2024 09:30:31 +0100 Subject: [PATCH] Add synthetic properties to JS engine for exclusion (#6178) * Add synthetic properties to JS engine for exclusion This fixes an issue where inputs would be declared as new variables, causing a "miss" when trying to read the input. * Add InputOutput workflows and tests for data exchange Introduce new Consumer and Provider JSON workflows to facilitate testing of input and output functionalities, ensuring seamless data exchange between processes. Implement corresponding tests to verify the correct reception and transmission of input data within the Provider workflow back to the Consumer, validating the setup with an assertion for expected output. Update the project configuration to include these workflows in the build output. --- .../Handlers/ConfigureEngineWithVariables.cs | 5 + .../Elsa.Workflows.ComponentTests.csproj | 6 + .../Scenarios/InputOutput/InputOutputTests.cs | 25 +++++ .../InputOutput/Workflows/consumer.json | 98 +++++++++++++++++ .../InputOutput/Workflows/provider.json | 104 ++++++++++++++++++ 5 files changed, 238 insertions(+) create mode 100644 test/component/Elsa.Workflows.ComponentTests/Scenarios/InputOutput/InputOutputTests.cs create mode 100644 test/component/Elsa.Workflows.ComponentTests/Scenarios/InputOutput/Workflows/consumer.json create mode 100644 test/component/Elsa.Workflows.ComponentTests/Scenarios/InputOutput/Workflows/provider.json diff --git a/src/modules/Elsa.JavaScript/Handlers/ConfigureEngineWithVariables.cs b/src/modules/Elsa.JavaScript/Handlers/ConfigureEngineWithVariables.cs index 76d4926c0..417c4f5eb 100644 --- a/src/modules/Elsa.JavaScript/Handlers/ConfigureEngineWithVariables.cs +++ b/src/modules/Elsa.JavaScript/Handlers/ConfigureEngineWithVariables.cs @@ -87,6 +87,11 @@ public class ConfigureEngineWithVariables(IOptions options) : INoti yield return inputDefinition.Name; } + foreach (var syntheticProperty in activityExecutionContext.Activity.SyntheticProperties) + { + yield return syntheticProperty.Key; + } + activityExecutionContext = activityExecutionContext.ParentActivityExecutionContext; } } diff --git a/test/component/Elsa.Workflows.ComponentTests/Elsa.Workflows.ComponentTests.csproj b/test/component/Elsa.Workflows.ComponentTests/Elsa.Workflows.ComponentTests.csproj index 1f285015a..84ef3ece2 100644 --- a/test/component/Elsa.Workflows.ComponentTests/Elsa.Workflows.ComponentTests.csproj +++ b/test/component/Elsa.Workflows.ComponentTests/Elsa.Workflows.ComponentTests.csproj @@ -82,6 +82,12 @@ Always + + Always + + + Always + diff --git a/test/component/Elsa.Workflows.ComponentTests/Scenarios/InputOutput/InputOutputTests.cs b/test/component/Elsa.Workflows.ComponentTests/Scenarios/InputOutput/InputOutputTests.cs new file mode 100644 index 000000000..ac648daf7 --- /dev/null +++ b/test/component/Elsa.Workflows.ComponentTests/Scenarios/InputOutput/InputOutputTests.cs @@ -0,0 +1,25 @@ +using Elsa.Workflows.ComponentTests.Abstractions; +using Elsa.Workflows.ComponentTests.Fixtures; +using Elsa.Workflows.Management; +using Elsa.Workflows.Runtime; +using Microsoft.Extensions.DependencyInjection; + +namespace Elsa.Workflows.ComponentTests.Scenarios.InputOutput; + +public class InputOutputTests(App app) : AppComponentTest(app) +{ + [Fact(DisplayName = "Input should be received by the Provider and should in turn be able to send it back to the Consumer.")] + public async Task InputShouldBeOutput() + { + const string workflowDefinitionVersionId = "4e993ab1b3d4e4a1"; + var workflowDefinitionService = Scope.ServiceProvider.GetRequiredService(); + var workflowInvoker = Scope.ServiceProvider.GetRequiredService(); + var variableManager = Scope.ServiceProvider.GetRequiredService(); + var workflowGraph = await workflowDefinitionService.FindWorkflowGraphAsync(workflowDefinitionVersionId); + var result = await workflowInvoker.InvokeAsync(workflowGraph!); + var variables = await variableManager.GetVariablesAsync(result.WorkflowState.Id); + var variableValue = variables.First().Value; + + Assert.Equal("Hello World!", variableValue); + } +} \ No newline at end of file diff --git a/test/component/Elsa.Workflows.ComponentTests/Scenarios/InputOutput/Workflows/consumer.json b/test/component/Elsa.Workflows.ComponentTests/Scenarios/InputOutput/Workflows/consumer.json new file mode 100644 index 000000000..46fbd3618 --- /dev/null +++ b/test/component/Elsa.Workflows.ComponentTests/Scenarios/InputOutput/Workflows/consumer.json @@ -0,0 +1,98 @@ +{ + "$schema": "https://elsaworkflows.io/schemas/workflow-definition/v3.0.0/schema.json", + "id": "4e993ab1b3d4e4a1", + "definitionId": "58dbd7bffa85a761", + "name": "Consumer", + "createdAt": "2024-12-04T16:49:20.593932\u002B00:00", + "version": 1, + "toolVersion": "3.3.0.0", + "variables": [ + { + "id": "67fcb9870af4c28e", + "name": "Variable1", + "typeName": "String", + "isArray": false, + "value": "", + "storageDriverTypeName": "Elsa.Workflows.WorkflowInstanceStorageDriver, Elsa.Workflows.Core" + } + ], + "inputs": [], + "outputs": [], + "outcomes": [], + "customProperties": { + "logPersistenceConfig": { + "default": { + "evaluationMode": "Strategy", + "strategyType": "Elsa.Workflows.LogPersistence.Strategies.Inherit, Elsa.Workflows.Core", + "expression": null + } + } + }, + "isReadonly": false, + "isSystem": false, + "isLatest": true, + "isPublished": true, + "options": { + "autoUpdateConsumingWorkflows": false + }, + "root": { + "id": "938f2c91bb759a6a", + "nodeId": "Workflow2:938f2c91bb759a6a", + "name": "Flowchart1", + "type": "Elsa.Flowchart", + "version": 1, + "customProperties": { + "notFoundConnections": [], + "canStartWorkflow": false, + "runAsynchronously": false + }, + "metadata": {}, + "activities": [ + { + "workflowDefinitionId": "780fbf96f1bb1e7e", + "workflowDefinitionVersionId": "640867552fc865d", + "latestAvailablePublishedVersion": 3, + "latestAvailablePublishedVersionId": "640867552fc865d", + "id": "8c1127e1193cd6e8", + "nodeId": "Workflow2:938f2c91bb759a6a:8c1127e1193cd6e8", + "name": "Output1", + "type": "Provider", + "version": 1, + "customProperties": { + "canStartWorkflow": false, + "runAsynchronously": false + }, + "metadata": { + "designer": { + "position": { + "x": -160, + "y": -280 + }, + "size": { + "width": 89.6953125, + "height": 50 + } + } + }, + "input1": { + "typeName": "Object", + "expression": { + "type": "Literal", + "value": "Hello World!" + }, + "memoryReference": { + "id": "8c1127e1193cd6e8:input-input-1" + } + }, + "output1": { + "typeName": "Object", + "memoryReference": { + "id": "67fcb9870af4c28e" + } + } + } + ], + "variables": [], + "connections": [] + } +} \ No newline at end of file diff --git a/test/component/Elsa.Workflows.ComponentTests/Scenarios/InputOutput/Workflows/provider.json b/test/component/Elsa.Workflows.ComponentTests/Scenarios/InputOutput/Workflows/provider.json new file mode 100644 index 000000000..27cebfffc --- /dev/null +++ b/test/component/Elsa.Workflows.ComponentTests/Scenarios/InputOutput/Workflows/provider.json @@ -0,0 +1,104 @@ +{ + "$schema": "https://elsaworkflows.io/schemas/workflow-definition/v3.0.0/schema.json", + "id": "5ba5a7e36d60549b", + "definitionId": "780fbf96f1bb1e7e", + "name": "Provider", + "createdAt": "2024-12-04T16:22:39.064075\u002B00:00", + "version": 1, + "toolVersion": "3.3.0.0", + "variables": [], + "inputs": [ + { + "uiHint": "singleline", + "storageDriverType": "Elsa.Workflows.WorkflowInstanceStorageDriver, Elsa.Workflows.Core", + "type": "Object", + "name": "Input1", + "displayName": "Input 1", + "description": "", + "category": "Primitives", + "isArray": false + } + ], + "outputs": [ + { + "type": "Object", + "name": "Output1", + "displayName": "Output 1", + "description": "", + "category": "Primitives", + "isArray": false + } + ], + "outcomes": [], + "customProperties": { + "logPersistenceConfig": { + "default": { + "evaluationMode": "Strategy", + "strategyType": "Elsa.Workflows.LogPersistence.Strategies.Inherit, Elsa.Workflows.Core", + "expression": null + } + } + }, + "isReadonly": false, + "isSystem": false, + "isLatest": true, + "isPublished": false, + "options": { + "usableAsActivity": true, + "autoUpdateConsumingWorkflows": true + }, + "root": { + "id": "85a5e1d9e487bfa4", + "nodeId": "Workflow1:85a5e1d9e487bfa4", + "name": "Flowchart1", + "type": "Elsa.Flowchart", + "version": 1, + "customProperties": { + "notFoundConnections": [], + "canStartWorkflow": false, + "runAsynchronously": false + }, + "metadata": {}, + "activities": [ + { + "outputName": { + "typeName": "String", + "expression": { + "type": "Literal", + "value": "Output1" + } + }, + "outputValue": { + "typeName": "Object", + "expression": { + "type": "JavaScript", + "value": "return getInput1()" + } + }, + "id": "985eb3bfb8d4dd3f", + "nodeId": "Workflow1:85a5e1d9e487bfa4:985eb3bfb8d4dd3f", + "name": "SetOutput1", + "type": "Elsa.SetOutput", + "version": 1, + "customProperties": { + "canStartWorkflow": false, + "runAsynchronously": false + }, + "metadata": { + "designer": { + "position": { + "x": -380, + "y": -220 + }, + "size": { + "width": 107.3203125, + "height": 50 + } + } + } + } + ], + "variables": [], + "connections": [] + } +} \ No newline at end of file