Skip to content

Commit 01b2749

Browse files
authored
fix: Fix ParseCapabilitiesIfUNIX for macOS/Linux and convert CI to GHA (#991)
1 parent cf9bb93 commit 01b2749

File tree

4 files changed

+130
-90
lines changed

4 files changed

+130
-90
lines changed

.github/workflows/unit-test.yml

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
name: Unit Tests
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
- 'release/**'
8+
pull_request:
9+
branches:
10+
- main
11+
- 'release/**'
12+
13+
jobs:
14+
test:
15+
runs-on: ${{ matrix.os }}
16+
17+
strategy:
18+
fail-fast: false
19+
matrix:
20+
os: [windows-latest, ubuntu-latest, macos-latest]
21+
include:
22+
- os: windows-latest
23+
framework: 'net48|net8.0'
24+
- os: ubuntu-latest
25+
framework: 'net8.0'
26+
- os: macos-latest
27+
framework: 'net8.0'
28+
29+
env:
30+
SOLUTION: 'Appium.Net.sln'
31+
BUILD_PLATFORM: 'Any CPU'
32+
BUILD_CONFIGURATION: 'Release'
33+
34+
steps:
35+
- name: Checkout code
36+
uses: actions/checkout@v4
37+
38+
- name: Setup .NET
39+
uses: actions/setup-dotnet@v4
40+
with:
41+
dotnet-version: '8.0.x'
42+
43+
- name: Setup NuGet (Windows)
44+
if: runner.os == 'Windows'
45+
uses: NuGet/setup-nuget@v2
46+
47+
- name: Restore NuGet packages (Windows)
48+
if: runner.os == 'Windows'
49+
run: nuget restore ${{ env.SOLUTION }}
50+
51+
- name: Restore NuGet packages (Linux/macOS)
52+
if: runner.os != 'Windows'
53+
run: dotnet restore ${{ env.SOLUTION }}
54+
55+
- name: Setup MSBuild (Windows)
56+
if: runner.os == 'Windows'
57+
uses: microsoft/setup-msbuild@v2
58+
59+
- name: Build solution (Windows)
60+
if: runner.os == 'Windows'
61+
run: |
62+
msbuild ${{ env.SOLUTION }} `
63+
/p:DeployOnBuild=true `
64+
/p:WebPublishMethod=Package `
65+
/p:PackageAsSingleFile=true `
66+
/p:SkipInvalidConfigurations=true `
67+
/p:DesktopBuildPackageLocation="${{ runner.temp }}\WebApp.zip" `
68+
/p:DeployIisAppPath="Default Web Site" `
69+
/p:Configuration=${{ env.BUILD_CONFIGURATION }} `
70+
/p:Platform="${{ env.BUILD_PLATFORM }}" `
71+
/m
72+
73+
- name: Build solution (Linux/macOS)
74+
if: runner.os != 'Windows'
75+
run: dotnet build ${{ env.SOLUTION }} --configuration ${{ env.BUILD_CONFIGURATION }}
76+
77+
- name: Setup Node.js
78+
uses: actions/setup-node@v4
79+
with:
80+
node-version: '20'
81+
82+
- name: Install Appium
83+
run: npm install -g appium
84+
85+
- name: Run .NET Framework 4.8 unit tests
86+
if: runner.os == 'Windows'
87+
run: |
88+
dotnet test `
89+
--no-build `
90+
--configuration ${{ env.BUILD_CONFIGURATION }} `
91+
--filter "AppiumLocalServerLaunchingTest|DirectConnectTest|AppiumClientConfigTest" `
92+
--framework net48 `
93+
--logger "trx;LogFileName=test-results-net48.trx" `
94+
./test/integration/Appium.Net.Integration.Tests.csproj
95+
96+
- name: Run .NET 8 unit tests
97+
run: |
98+
dotnet test \
99+
--no-build \
100+
--configuration ${{ env.BUILD_CONFIGURATION }} \
101+
--filter "AppiumLocalServerLaunchingTest|DirectConnectTest|AppiumClientConfigTest" \
102+
--framework net8.0 \
103+
--logger "trx;LogFileName=test-results-net8-${{ matrix.os }}.trx" \
104+
./test/integration/Appium.Net.Integration.Tests.csproj
105+
shell: bash
106+
107+
- name: Publish test results
108+
uses: dorny/test-reporter@v1
109+
if: always()
110+
with:
111+
name: Test Results (${{ matrix.os }})
112+
path: '**/test-results-*.trx'
113+
reporter: dotnet-trx

azure-pipelines.yml

Lines changed: 0 additions & 50 deletions
This file was deleted.

src/Appium.Net/Appium/Service/AppiumLocalService.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ private static HttpClient CreateHttpClientInstance()
7979
/// </summary>
8080
public event DataReceivedEventHandler OutputDataReceived;
8181

82+
/// <summary>
83+
/// Event that can be used to capture the error output of the service
84+
/// </summary>
85+
public event DataReceivedEventHandler ErrorDataReceived;
86+
8287
/// <summary>
8388
/// Starts the defined Appium server.
8489
/// <remarks>
@@ -115,7 +120,9 @@ private async Task StartAsync()
115120
}
116121

117122
Service.StartInfo.RedirectStandardOutput = true;
123+
Service.StartInfo.RedirectStandardError = true;
118124
Service.OutputDataReceived += (sender, e) => OutputDataReceived?.Invoke(this, e);
125+
Service.ErrorDataReceived += (sender, e) => ErrorDataReceived?.Invoke(this, e);
119126

120127
bool isLaunched = false;
121128
string msgTxt =
@@ -127,6 +134,7 @@ private async Task StartAsync()
127134
Service.Start();
128135

129136
Service.BeginOutputReadLine();
137+
Service.BeginErrorReadLine();
130138
}
131139
catch (Exception e)
132140
{

src/Appium.Net/Appium/Service/Options/OptionCollector.cs

Lines changed: 9 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
using System;
1616
using System.Collections.Generic;
17+
using System.Text.Json;
1718

1819
namespace OpenQA.Selenium.Appium.Service.Options
1920
{
@@ -39,7 +40,7 @@ public OptionCollector AddArguments(KeyValuePair<string, string> arguments)
3940
/// Adds/merges server-specific capabilities
4041
/// </summary>
4142
/// <param name="options">is an instance of OpenQA.Selenium.Remote.AppiumOptions</param>
42-
/// <returns>the self-reference</returns>
43+
/// <returns>the self-reference</returns>
4344
public OptionCollector AddCapabilities(AppiumOptions options)
4445
{
4546
if (this.options == null)
@@ -128,48 +129,16 @@ private string ParseCapabilitiesIfWindows()
128129

129130
private string ParseCapabilitiesIfUNIX()
130131
{
131-
string result = string.Empty;
132-
133-
if (options != null)
132+
if (options == null)
134133
{
135-
IDictionary<string, object> capabilitiesDictionary = options.ToDictionary();
136-
137-
foreach (var item in capabilitiesDictionary)
138-
{
139-
object value = item.Value;
140-
141-
if (value == null)
142-
{
143-
continue;
144-
}
145-
146-
if (typeof(string).IsAssignableFrom(value.GetType()))
147-
{
148-
value = $"\"{value}\"";
149-
;
150-
}
151-
152-
else
153-
{
154-
if (typeof(bool).IsAssignableFrom(value.GetType()))
155-
{
156-
value = Convert.ToString(value).ToLowerInvariant();
157-
}
158-
}
159-
160-
string key = $"\"{item.Key}\"";
161-
if (string.IsNullOrEmpty(result))
162-
{
163-
result = $"{key}: {value}";
164-
}
165-
else
166-
{
167-
result = result + ", " + key + ": " + value;
168-
}
169-
}
134+
return string.Empty;
170135
}
171136

172-
return "'{" + result + "}'";
137+
// Serialize to JSON and escape double quotes so they survive argument parsing
138+
var json = JsonSerializer.Serialize(options.ToDictionary());
139+
// Escape double quotes with backslash for shell argument
140+
var escaped = json.Replace("\"", "\\\"");
141+
return $"\"{escaped}\"";
173142
}
174143

175144
/// <summary>

0 commit comments

Comments
 (0)