diff --git a/test/unit/Elsa.Activities.UnitTests/Console/ReadLineTests.cs b/test/unit/Elsa.Activities.UnitTests/Console/ReadLineTests.cs
new file mode 100644
index 000000000..d89e925ae
--- /dev/null
+++ b/test/unit/Elsa.Activities.UnitTests/Console/ReadLineTests.cs
@@ -0,0 +1,104 @@
+using Elsa.Extensions;
+using Elsa.Testing.Shared;
+using Elsa.Workflows;
+using Microsoft.Extensions.DependencyInjection;
+using NSubstitute;
+
+namespace Elsa.Activities.UnitTests.Console;
+
+///
+/// Unit tests for the activity.
+///
+public class ReadLineTests
+{
+ private readonly TextReader _mockTextReader;
+ private readonly IStandardInStreamProvider _mockProvider;
+
+ public ReadLineTests()
+ {
+ _mockTextReader = Substitute.For();
+ _mockProvider = Substitute.For();
+ _mockProvider.GetTextReader().Returns(_mockTextReader);
+ }
+
+ [Theory(DisplayName = "ReadLine reads text from input and completes successfully")]
+ [InlineData("Hello, World!")]
+ [InlineData("Test input")]
+ [InlineData("")]
+ [InlineData(" ")]
+ [InlineData("\t")]
+ public async Task Should_Read_Text_From_Input_And_Complete(string inputText)
+ {
+ // Arrange
+ var readLine = new ReadLine();
+
+ // Act
+ var context = await ExecuteAsync(readLine, inputText);
+
+ // Assert
+ Assert.Equal(ActivityStatus.Completed, context.Status);
+ var result = (string)context.GetActivityOutput(() => readLine.Result)!;
+ Assert.Equal(inputText, result);
+ }
+
+ [Fact(DisplayName = "ReadLine uses provided stream provider")]
+ public async Task Should_Use_Provided_Stream_Provider()
+ {
+ // Act
+ await ExecuteAsync(new ReadLine());
+
+ // Assert
+ _mockProvider.Received(1).GetTextReader();
+ _mockTextReader.Received(1).ReadLine();
+ }
+
+ [Fact(DisplayName = "ReadLine handles null return value from stream")]
+ public async Task Should_Handle_Null_Return_Value()
+ {
+ // Arrange
+ var readLine = new ReadLine();
+
+ // Act
+ var context = await ExecuteAsync(readLine, null);
+
+ // Assert - The null-forgiving operator in ReadLine implementation means it expects non-null,
+ // but null can occur at end of stream. Verify the behavior stores null.
+ var result = context.GetActivityOutput(() => readLine.Result);
+ Assert.Null(result);
+ }
+
+ [Fact(DisplayName = "ReadLine uses default provider when none is registered")]
+ public async Task Should_Use_Default_Provider_When_None_Registered()
+ {
+ // Arrange
+ var readLine = new ReadLine();
+ const string expectedInput = "Default provider test";
+ var originalConsoleIn = System.Console.In;
+
+ try
+ {
+ // Redirect Console.In to our StringReader
+ System.Console.SetIn(new StringReader(expectedInput));
+
+ // Act
+ var context = await new ActivityTestFixture(readLine).ExecuteAsync();
+
+ // Assert
+ var result = (string)context.GetActivityOutput(() => readLine.Result)!;
+ Assert.Equal(expectedInput, result);
+ }
+ finally
+ {
+ // Restore original Console.In
+ System.Console.SetIn(originalConsoleIn);
+ }
+ }
+
+ private Task ExecuteAsync(ReadLine readLine, string? inputText = "Test")
+ {
+ _mockTextReader.ReadLine().Returns(inputText);
+ return new ActivityTestFixture(readLine)
+ .ConfigureServices(services => services.AddSingleton(_mockProvider))
+ .ExecuteAsync();
+ }
+}