diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dc8e642..24960f2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,6 +51,8 @@ jobs: dotnet build tests/OpenClaw.Tray.Tests -c Debug - name: Run Shared Tests + env: + OPENCLAW_RUN_INTEGRATION: 1 run: > dotnet test tests/OpenClaw.Shared.Tests --no-build diff --git a/tests/OpenClaw.Shared.Tests/SystemRunTests.cs b/tests/OpenClaw.Shared.Tests/SystemRunTests.cs index fa13c58..5845c4c 100644 --- a/tests/OpenClaw.Shared.Tests/SystemRunTests.cs +++ b/tests/OpenClaw.Shared.Tests/SystemRunTests.cs @@ -248,6 +248,16 @@ public class SystemRunTests var res = await cap.ExecuteAsync(req); Assert.True(res.Ok, res.Error); + + var json = JsonSerializer.Serialize(res.Payload); + using var doc = JsonDocument.Parse(json); + var root = doc.RootElement; + Assert.Equal("git status --short", root.GetProperty("cmdText").GetString()); + var plan = root.GetProperty("plan"); + var argv = plan.GetProperty("argv"); + Assert.Equal("git", argv[0].GetString()); + Assert.Equal("status", argv[1].GetString()); + Assert.Equal("--short", argv[2].GetString()); } [Fact] @@ -263,6 +273,14 @@ public class SystemRunTests var res = await cap.ExecuteAsync(req); Assert.True(res.Ok, res.Error); + + var json = JsonSerializer.Serialize(res.Payload); + using var doc = JsonDocument.Parse(json); + var root = doc.RootElement; + Assert.Equal("\"echo hello\"", root.GetProperty("cmdText").GetString()); + var argv = root.GetProperty("plan").GetProperty("argv"); + Assert.Single(argv.EnumerateArray()); + Assert.Equal("echo hello", argv[0].GetString()); } [Fact] diff --git a/tests/OpenClaw.Shared.Tests/WebSocketClientBaseTests.cs b/tests/OpenClaw.Shared.Tests/WebSocketClientBaseTests.cs index 05b0441..a434baf 100644 --- a/tests/OpenClaw.Shared.Tests/WebSocketClientBaseTests.cs +++ b/tests/OpenClaw.Shared.Tests/WebSocketClientBaseTests.cs @@ -75,12 +75,11 @@ public class WebSocketClientBaseTests [InlineData("https://gateway.example.com", "wss://gateway.example.com")] [InlineData("ws://localhost:18789", "ws://localhost:18789")] [InlineData("wss://gateway.example.com", "wss://gateway.example.com")] - public void Constructor_NormalizesUrl(string input, string _) + public void Constructor_NormalizesUrl(string input, string expected) { var client = new TestWebSocketClient(input, "test-token", _logger); - // GatewayUrlForDisplay is the sanitized version — just verify it's set - Assert.NotNull(client.TestGatewayUrlForDisplay); - Assert.DoesNotContain("@", client.TestGatewayUrlForDisplay); // credentials stripped + Assert.Equal(expected, client.TestGatewayUrlForDisplay); + Assert.DoesNotContain("@", client.TestGatewayUrlForDisplay); client.Dispose(); } @@ -132,6 +131,7 @@ public class WebSocketClientBaseTests public void Constructor_WithCredentialUrl_StripsFromDisplay() { var client = new TestWebSocketClient("ws://user:pass@localhost:18789", "token", _logger); + Assert.Equal("ws://localhost:18789", client.TestGatewayUrlForDisplay); Assert.DoesNotContain("pass", client.TestGatewayUrlForDisplay); client.Dispose(); } @@ -245,7 +245,9 @@ public class WebSocketClientBaseTests client.StatusChanged += (_, s) => statuses.Add(s); await client.ConnectAsync(); - await Task.Delay(150); + await WaitForConditionAsync( + () => statuses.Count(s => s == ConnectionStatus.Connecting) >= 2, + TimeSpan.FromSeconds(2)); Assert.Contains(ConnectionStatus.Error, statuses); Assert.True(statuses.Count(s => s == ConnectionStatus.Connecting) >= 2); @@ -265,7 +267,7 @@ public class WebSocketClientBaseTests client.StatusChanged += (_, s) => statuses.Add(s); await client.ConnectAsync(); - await Task.Delay(150); + await Task.Delay(250); Assert.Contains(ConnectionStatus.Error, statuses); Assert.Single(statuses, s => s == ConnectionStatus.Connecting); @@ -273,6 +275,18 @@ public class WebSocketClientBaseTests client.Dispose(); } + + private static async Task WaitForConditionAsync(Func predicate, TimeSpan timeout) + { + var start = DateTime.UtcNow; + while (!predicate()) + { + if (DateTime.UtcNow - start > timeout) + throw new TimeoutException("Condition was not met before the timeout."); + + await Task.Delay(25); + } + } } public class TestLogger : IOpenClawLogger diff --git a/tests/OpenClaw.Tray.Tests/MenuDisplayHelperTests.cs b/tests/OpenClaw.Tray.Tests/MenuDisplayHelperTests.cs index 78488e4..ef3090e 100644 --- a/tests/OpenClaw.Tray.Tests/MenuDisplayHelperTests.cs +++ b/tests/OpenClaw.Tray.Tests/MenuDisplayHelperTests.cs @@ -48,16 +48,15 @@ public class MenuDisplayHelperTests } [Theory] - [InlineData("OK")] - [InlineData("Connected")] - [InlineData("RUNNING")] - [InlineData("Error")] - [InlineData("Connecting")] - [InlineData("RECONNECTING")] - public void GetChannelStatusIcon_CaseInsensitive(string status) + [InlineData("OK", "🟢")] + [InlineData("Connected", "🟢")] + [InlineData("RUNNING", "🟢")] + [InlineData("Error", "🔴")] + [InlineData("Connecting", "🟡")] + [InlineData("RECONNECTING", "🟡")] + public void GetChannelStatusIcon_CaseInsensitive(string status, string expected) { - // Should not return the neutral fallback - Assert.NotEqual("⚪", MenuDisplayHelper.GetChannelStatusIcon(status)); + Assert.Equal(expected, MenuDisplayHelper.GetChannelStatusIcon(status)); } [Theory]