elsa-core/test/integration/Elsa.Activities.IntegrationTests/Branching/SwitchTests.cs
Sipke Schoorstra fbe9ca64f0
Fix Switch activity behavior and add testing utilities for RunWorkflowResult and improve (#7151)
* Add testing utilities for `RunWorkflowResult` and improve `Switch` activity behavior

- Introduced `RunWorkflowResultAssertions` for xUnit-based workflow testing.
- Added `RunWorkflowResultExtensions` for journal-based activity execution context handling.
- Refactored `Switch` activity to track scheduled activities and correctly complete execution when all scheduled activities finish.
- Marked `RunActivityExtensions` methods as obsolete, recommending the use of `WorkflowTestFixture`.

* Update src/common/Elsa.Testing.Shared.Integration/RunActivityExtensions.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/modules/Elsa.Workflows.Core/Activities/Switch.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Add XML documentation to Switch activity callback method (#7152)

* Initial plan

* Add XML documentation to OnChildActivityCompletedAsync method

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>
2025-12-19 17:05:12 +01:00

288 lines
9.1 KiB
C#

using Elsa.Testing.Shared;
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Xunit.Abstractions;
namespace Elsa.Activities.IntegrationTests.Branching;
/// <summary>
/// Integration tests for Switch activity.
/// </summary>
public class SwitchTests(ITestOutputHelper testOutputHelper)
{
private readonly WorkflowTestFixture _fixture = new(testOutputHelper);
[Fact(DisplayName = "Switch completes immediately when no matches and no activities scheduled")]
public async Task Switch_CompletesImmediately_WhenNoMatchesAndNoActivitiesScheduled()
{
// Arrange
var case1Activity = new WriteLine("Case 1");
var case2Activity = new WriteLine("Case 2");
var switchActivity = new Switch
{
Cases =
{
new("Case 1", () => false, case1Activity),
new("Case 2", () => false, case2Activity)
},
Default = null
};
// Act
var result = await _fixture.RunActivityAsync(switchActivity);
// Assert
result.AssertActivityCompleted(switchActivity);
result.AssertActivitiesNotExecuted(case1Activity, case2Activity);
}
[Fact(DisplayName = "Switch completes immediately when no matches but has null default")]
public async Task Switch_CompletesImmediately_WhenNoMatchesAndDefaultIsNull()
{
// Arrange
var case1Activity = new WriteLine("Case 1");
var switchActivity = new Switch
{
Cases =
{
new("Case 1", () => false, case1Activity)
}
};
// Act
var result = await _fixture.RunActivityAsync(switchActivity);
// Assert
result.AssertActivityCompleted(switchActivity);
result.AssertActivityNotExecuted(case1Activity);
}
[Fact(DisplayName = "Switch schedules default activity when no cases match")]
public async Task Switch_SchedulesDefaultActivity_WhenNoCasesMatch()
{
// Arrange
var case1Activity = new WriteLine("Case 1");
var case2Activity = new WriteLine("Case 2");
var defaultActivity = new WriteLine("Default");
var switchActivity = new Switch
{
Cases =
{
new("Case 1", () => false, case1Activity),
new("Case 2", () => false, case2Activity)
},
Default = defaultActivity
};
// Act
var result = await _fixture.RunActivityAsync(switchActivity);
// Assert
result.AssertActivitiesCompleted(switchActivity, defaultActivity);
result.AssertActivitiesNotExecuted(case1Activity, case2Activity);
}
[Fact(DisplayName = "Switch in MatchFirst mode schedules only first matching case")]
public async Task Switch_InMatchFirstMode_SchedulesOnlyFirstMatchingCase()
{
// Arrange
var case1Activity = new WriteLine("Case 1");
var case2Activity = new WriteLine("Case 2");
var case3Activity = new WriteLine("Case 3");
var switchActivity = new Switch
{
Mode = new(SwitchMode.MatchFirst),
Cases =
{
new("Case 1", () => false, case1Activity),
new("Case 2", () => true, case2Activity),
new("Case 3", () => true, case3Activity)
}
};
// Act
var result = await _fixture.RunActivityAsync(switchActivity);
// Assert
result.AssertActivitiesCompleted(switchActivity, case2Activity);
result.AssertActivitiesNotExecuted(case1Activity, case3Activity);
}
[Fact(DisplayName = "Switch in MatchAny mode schedules all matching cases")]
public async Task Switch_InMatchAnyMode_SchedulesAllMatchingCases()
{
// Arrange
var case1Activity = new WriteLine("Case 1");
var case2Activity = new WriteLine("Case 2");
var case3Activity = new WriteLine("Case 3");
var case4Activity = new WriteLine("Case 4");
var case5Activity = new WriteLine("Case 5");
var switchActivity = new Switch
{
Mode = new(SwitchMode.MatchAny),
Cases =
{
new("Case 1", () => false, case1Activity),
new("Case 2", () => true, case2Activity),
new("Case 3", () => true, case3Activity),
new("Case 4", () => false, case4Activity),
new("Case 5", () => true, case5Activity)
}
};
// Act
var result = await _fixture.RunActivityAsync(switchActivity);
// Assert
result.AssertActivitiesCompleted(switchActivity, case2Activity, case3Activity, case5Activity);
result.AssertActivitiesNotExecuted(case1Activity, case4Activity);
}
[Fact(DisplayName = "Switch completes only after all scheduled activities complete")]
public async Task Switch_CompletesOnlyAfterAllScheduledActivitiesComplete()
{
// Arrange
var activity1 = new WriteLine("Activity 1");
var activity2 = new WriteLine("Activity 2");
var activity3 = new WriteLine("Activity 3");
var switchActivity = new Switch
{
Mode = new(SwitchMode.MatchAny),
Cases =
{
new("Case 1", () => true, activity1),
new("Case 2", () => true, activity2),
new("Case 3", () => true, activity3)
}
};
// Act
var result = await _fixture.RunActivityAsync(switchActivity);
// Assert
result.AssertActivitiesCompleted(switchActivity, activity1, activity2, activity3);
}
[Fact(DisplayName = "Switch completes after default activity completes")]
public async Task Switch_CompletesAfterDefaultActivityCompletes()
{
// Arrange
var case1Activity = new WriteLine("Case 1");
var defaultActivity = new WriteLine("Default Activity");
var switchActivity = new Switch
{
Cases =
{
new("Case 1", () => false, case1Activity)
},
Default = defaultActivity
};
// Act
var result = await _fixture.RunActivityAsync(switchActivity);
// Assert
result.AssertActivitiesCompleted(switchActivity, defaultActivity);
result.AssertActivityNotExecuted(case1Activity);
}
[Fact(DisplayName = "Switch with nested activities completes after all complete")]
public async Task Switch_WithNestedActivities_CompletesAfterAllComplete()
{
// Arrange
var nestedSequence1 = new Sequence
{
Activities =
{
new WriteLine("Nested 1A"),
new WriteLine("Nested 1B")
}
};
var nestedSequence2 = new Sequence
{
Activities =
{
new WriteLine("Nested 2A"),
new WriteLine("Nested 2B")
}
};
var switchActivity = new Switch
{
Mode = new(SwitchMode.MatchAny),
Cases =
{
new("Case 1", () => true, nestedSequence1),
new("Case 2", () => true, nestedSequence2)
}
};
// Act
var result = await _fixture.RunActivityAsync(switchActivity);
// Assert
result.AssertActivitiesCompleted(switchActivity, nestedSequence1, nestedSequence2);
}
[Fact(DisplayName = "Switch in MatchFirst mode with single match")]
public async Task Switch_InMatchFirstMode_WithSingleMatch()
{
// Arrange
var case1Activity = new WriteLine("Case 1");
var case2Activity = new WriteLine("Case 2");
var case3Activity = new WriteLine("Case 3");
var switchActivity = new Switch
{
Mode = new(SwitchMode.MatchFirst),
Cases =
{
new("Case 1", () => false, case1Activity),
new("Case 2", () => false, case2Activity),
new("Case 3", () => true, case3Activity)
}
};
// Act
var result = await _fixture.RunActivityAsync(switchActivity);
// Assert
result.AssertActivitiesCompleted(switchActivity, case3Activity);
result.AssertActivitiesNotExecuted(case1Activity, case2Activity);
}
[Fact(DisplayName = "Switch evaluates conditions with expression context")]
public async Task Switch_EvaluatesConditionsWithExpressionContext()
{
// Arrange
var conditionValue = true;
var case1Activity = new WriteLine("Case 1");
var case2Activity = new WriteLine("Case 2");
var case3Activity = new WriteLine("Case 3");
var switchActivity = new Switch
{
Cases =
{
new("Case 1", _ => false, case1Activity),
new("Case 2", _ => conditionValue, case2Activity),
new("Case 3", _ => false, case3Activity)
}
};
// Act
var result = await _fixture.RunActivityAsync(switchActivity);
// Assert
result.AssertActivitiesCompleted(switchActivity, case2Activity);
result.AssertActivitiesNotExecuted(case1Activity, case3Activity);
}
}