Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions .github/workflows/functional-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v7
uses: actions/checkout@v6

- name: Setup .NET
uses: actions/setup-dotnet@v5
Expand All @@ -52,16 +52,16 @@ jobs:
java-version: '17'

- name: Setup Android SDK
uses: android-actions/setup-android@v4
uses: android-actions/setup-android@v3

- name: AVD cache
uses: actions/cache@v6
uses: actions/cache@v5
id: avd-cache
with:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-${{ matrix.api-level }}-${{ matrix.target }}
key: avd-${{ matrix.api-level }}

- name: Create AVD and generate snapshot for caching
if: steps.avd-cache.outputs.cache-hit != 'true'
Expand Down Expand Up @@ -118,7 +118,7 @@ jobs:

# Common: Publish results
- name: Publish test results
uses: dorny/test-reporter@v3
uses: dorny/test-reporter@v2
if: always()
with:
name: Android Test Results (API ${{ matrix.api-level }})
Expand All @@ -127,7 +127,7 @@ jobs:

- name: Save server output
if: always()
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v6
with:
name: appium-android-${{ matrix.api-level }}.log
path: appium*.log
Expand All @@ -145,7 +145,7 @@ jobs:
steps:
# Common: Checkout and setup
- name: Checkout code
uses: actions/checkout@v7
uses: actions/checkout@v6

- name: Setup .NET
uses: actions/setup-dotnet@v5
Expand Down Expand Up @@ -214,7 +214,7 @@ jobs:
./test/integration/Appium.Net.Integration.Tests.csproj

- name: Publish test results
uses: dorny/test-reporter@v3
uses: dorny/test-reporter@v2
if: always()
with:
name: iOS Test Results
Expand All @@ -223,7 +223,7 @@ jobs:

- name: Save server output
if: always()
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v6
with:
name: appium-ios.log
path: |
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-nuget.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
runs-on: windows-latest

steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v6

- name: Setup .NET Core
uses: actions/setup-dotnet@v5
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/unit-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v7
uses: actions/checkout@v6

- name: Setup .NET
uses: actions/setup-dotnet@v5
Expand All @@ -42,7 +42,7 @@ jobs:

- name: Setup NuGet (Windows)
if: runner.os == 'Windows'
uses: NuGet/setup-nuget@v4
uses: NuGet/setup-nuget@v2

- name: Restore NuGet packages (Windows)
if: runner.os == 'Windows'
Expand Down Expand Up @@ -105,7 +105,7 @@ jobs:
shell: bash

- name: Publish test results
uses: dorny/test-reporter@v3
uses: dorny/test-reporter@v2
if: always()
with:
name: Test Results (${{ matrix.os }})
Expand Down
18 changes: 4 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,7 @@
[![Build and deploy NuGet package](https://github.com/appium/dotnet-client/actions/workflows/release-nuget.yml/badge.svg)](https://github.com/appium/dotnet-client/actions/workflows/release-nuget.yml)
[![NuGet Downloads](https://img.shields.io/nuget/dt/Appium.Webdriver.svg)](https://www.nuget.org/packages/Appium.Webdriver)

----

[![Functional Tests](https://github.com/appium/dotnet-client/actions/workflows/functional-test.yml/badge.svg)](https://github.com/appium/dotnet-client/actions/workflows/functional-test.yml)
[![Functional Tests (Android)](https://github.com/appium/dotnet-client/actions/workflows/functional-android-test.yml/badge.svg)](https://github.com/appium/dotnet-client/actions/workflows/functional-android-test.yml)
[![Functional Tests (iOS)](https://github.com/appium/dotnet-client/actions/workflows/functional-ios-test.yml/badge.svg)](https://github.com/appium/dotnet-client/actions/workflows/functional-ios-test.yml)
[![Unit Tests](https://github.com/appium/dotnet-client/actions/workflows/unit-test.yml/badge.svg)](https://github.com/appium/dotnet-client/actions/workflows/unit-test.yml)

----
[![Build Status](https://dev.azure.com/AppiumCI/dotnet-client/_apis/build/status/appium.dotnet-client?branchName=main)](https://dev.azure.com/AppiumCI/dotnet-client/_build/latest?definitionId=68&branchName=main)

[![Help Wanted](https://img.shields.io/github/issues-raw/appium/dotnet-client/HelpWanted?style=plastic&logo=github&logoColor=blue&label=Help%20Wanted%20issues&color=red
)](https://github.com/appium/dotnet-client/issues?q=is%3Aopen+is%3Aissue+label%3AHelpWanted)
Expand All @@ -28,16 +21,12 @@ For example, some changes in the Selenium binding could break the Appium client.

|Appium .NET Client| Selenium Binding | .NET Version |
|----|----|----|
|`8.3.0` |`4.44.0` |.NET Standard 2.0 |
|`8.2.0` |`4.36.0` |.NET Standard 2.0 |
|`7.2.0` |`4.29.0` |.NET Standard 2.0 |
|`7.1.0` |`4.28.0` |.NET Standard 2.0 |
|`8.0.1` |`4.36.0` |.NET Standard 2.0 |
|`7.0.0` |`4.27.0` |.NET Standard 2.0 |
|`6.0.1` |`4.26.1` |.NET Standard 2.0 |
|`6.0.0` |`4.25.0` |.NET Standard 2.0 |
|`5.2.0` |`4.24.0` |.NET 6.0, .NET Framework 4.8 |
|`5.1.0` |`4.23.0` |.NET 6.0, .NET Framework 4.8 |
|`5.0.0` |`4.0.0` - `4.22.0` | .NET 6.0, .NET Framework 4.8 |
|`4.4.5` |`3.141.0` |.NET Standard 2.0, .NET Framework 4.8 |

> [!Note]
> We only raise the minimum required Selenium.WebDriver version when a newer Selenium release introduces changes that require updates in the Appium .NET Client.
Expand Down Expand Up @@ -114,6 +103,7 @@ Dependencies:
- [Selenium.WebDriver](http://www.nuget.org/packages/Selenium.WebDriver/)
- [System.Drawing.Common](https://www.nuget.org/packages/System.Drawing.Common/)

Note: we will NOT publish a signed version of this assembly since the dependencies we access through NuGet do not have a signed version - thus breaking the chain and causing us headaches. With that said, you are more than welcome to download the code and build a signed version yourself.

## Usage

Expand Down
8 changes: 4 additions & 4 deletions src/Appium.Net/Appium.Net.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<Product>Dotnet-Client</Product>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Copyright>Copyright © 2014-2026</Copyright>
<Copyright>Copyright © 2023</Copyright>
<PackageProjectUrl>https://appium.io</PackageProjectUrl>
<RepositoryUrl>https://github.com/appium/dotnet-client</RepositoryUrl>
<RepositoryType>git</RepositoryType>
Expand Down Expand Up @@ -39,11 +39,11 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.300">
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Selenium.WebDriver" Version="4.44.0" />
<PackageReference Include="System.Drawing.Common" Version="10.0.8" />
<PackageReference Include="Selenium.WebDriver" Version="4.36.0" />
<PackageReference Include="System.Drawing.Common" Version="8.0.10" />
</ItemGroup>
</Project>
68 changes: 27 additions & 41 deletions src/Appium.Net/Appium/Android/AndroidCommandExecutionHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,48 +12,43 @@
//See the License for the specific language governing permissions and
//limitations under the License.

using OpenQA.Selenium.Appium.Enums;
using OpenQA.Selenium.Appium.Interfaces;
using System;
using OpenQA.Selenium.Appium.Interfaces;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using OpenQA.Selenium.Appium.Enums;

namespace OpenQA.Selenium.Appium.Android
{
public sealed class AndroidCommandExecutionHelper : AppiumCommandExecutionHelper
{
public static string GetCurrentActivity(IExecuteMethod executeMethod)
{
return executeMethod.Execute(DriverCommand.ExecuteScript, new Dictionary<string, object>
{
return executeMethod.Execute(DriverCommand.ExecuteScript, new Dictionary<string, object> {
["script"] = "mobile:getCurrentActivity",
["args"] = Array.Empty<object>()
}).Value.ToString();
}

public static string GetCurrentPackage(IExecuteMethod executeMethod)
{
return executeMethod.Execute(DriverCommand.ExecuteScript, new Dictionary<string, object>
{
return executeMethod.Execute(DriverCommand.ExecuteScript, new Dictionary<string, object> {
["script"] = "mobile:getCurrentPackage",
["args"] = Array.Empty<object>()
}).Value.ToString();
}

#region Device Network

public static void ToggleLocationServices(IExecuteMethod executeMethod)
{
executeMethod.Execute(DriverCommand.ExecuteScript, new Dictionary<string, object>
{
public static void ToggleLocationServices(IExecuteMethod executeMethod) {
executeMethod.Execute(DriverCommand.ExecuteScript, new Dictionary<string, object> {
["script"] = "mobile:toggleGps",
["args"] = Array.Empty<object>()
});
}

public static void GsmCall(IExecuteMethod executeMethod, string number, GsmCallActions gsmCallAction)
{
executeMethod.Execute(DriverCommand.ExecuteScript, new Dictionary<string, object>
{
public static void GsmCall(IExecuteMethod executeMethod, string number, GsmCallActions gsmCallAction) {
executeMethod.Execute(DriverCommand.ExecuteScript, new Dictionary<string, object> {
["script"] = "mobile:gsmCall",
["args"] = new object[] {
new Dictionary<string, object>() {
Expand All @@ -64,10 +59,8 @@ public static void GsmCall(IExecuteMethod executeMethod, string number, GsmCallA
});
}

public static void SendSms(IExecuteMethod executeMethod, string number, string message)
{
executeMethod.Execute(DriverCommand.ExecuteScript, new Dictionary<string, object>
{
public static void SendSms(IExecuteMethod executeMethod, string number, string message) {
executeMethod.Execute(DriverCommand.ExecuteScript, new Dictionary<string, object> {
["script"] = "mobile:sendSms",
["args"] = new object[] {
new Dictionary<string, object>() {
Expand All @@ -80,8 +73,7 @@ public static void SendSms(IExecuteMethod executeMethod, string number, string m

public static void SetGsmStrength(IExecuteMethod executeMethod, GsmSignalStrength gsmSignalStrength)
{
executeMethod.Execute(DriverCommand.ExecuteScript, new Dictionary<string, object>
{
executeMethod.Execute(DriverCommand.ExecuteScript, new Dictionary<string, object> {
["script"] = "mobile:gsmSignal",
["args"] = new object[] {
new Dictionary<string, object>() {
Expand All @@ -93,8 +85,7 @@ public static void SetGsmStrength(IExecuteMethod executeMethod, GsmSignalStrengt

public static void SetGsmVoice(IExecuteMethod executeMethod, GsmVoiceState gsmVoiceState)
{
executeMethod.Execute(DriverCommand.ExecuteScript, new Dictionary<string, object>
{
executeMethod.Execute(DriverCommand.ExecuteScript, new Dictionary<string, object> {
["script"] = "mobile:gsmVoice",
["args"] = new object[] {
new Dictionary<string, object>()
Expand All @@ -109,10 +100,8 @@ public static void SetGsmVoice(IExecuteMethod executeMethod, GsmVoiceState gsmVo

#region Device Performance

public static object[] GetPerformanceDataTypes(IExecuteMethod executeMethod)
{
return executeMethod.Execute(DriverCommand.ExecuteScript, new Dictionary<string, object>
{
public static object[] GetPerformanceDataTypes(IExecuteMethod executeMethod) {
return executeMethod.Execute(DriverCommand.ExecuteScript, new Dictionary<string, object> {
["script"] = "mobile:getPerformanceDataTypes",
["args"] = Array.Empty<object>()
}).Value as object[];
Expand All @@ -121,15 +110,15 @@ public static object[] GetPerformanceDataTypes(IExecuteMethod executeMethod)
private static Dictionary<string, object> CreatePerformanceDataRequest(params (string Name, object Value)[] args)
{
var argDict = new Dictionary<string, object>();
foreach (var (Name, Value) in args)
foreach (var arg in args)
{
argDict[Name] = Value;
argDict[arg.Name] = arg.Value;
}

return new Dictionary<string, object>
{
["script"] = "mobile:getPerformanceData",
["args"] = argDict.Count == 0 ? [] : new object[] { argDict }
["args"] = argDict.Count == 0 ? Array.Empty<object>() : new object[] { argDict }
};
}

Expand Down Expand Up @@ -158,17 +147,15 @@ public static object[] GetPerformanceData(IExecuteMethod executeMethod, string p

public static void OpenNotifications(IExecuteMethod executeMethod)
{
executeMethod.Execute(DriverCommand.ExecuteScript, new Dictionary<string, object>
{
executeMethod.Execute(DriverCommand.ExecuteScript, new Dictionary<string, object> {
["script"] = "mobile:openNotifications",
["args"] = Array.Empty<object>()
});
}

public static IDictionary<string, object> GetSystemBars(IExecuteMethod executeMethod)
{
return executeMethod.Execute(DriverCommand.ExecuteScript, new Dictionary<string, object>
{
return executeMethod.Execute(DriverCommand.ExecuteScript, new Dictionary<string, object> {
["script"] = "mobile:getSystemBars",
["args"] = Array.Empty<object>()
}).Value as IDictionary<string, object>;
Expand All @@ -177,11 +164,10 @@ public static IDictionary<string, object> GetSystemBars(IExecuteMethod executeMe
public static float GetDisplayDensity(IExecuteMethod executeMethod)
{
return Convert.ToSingle(
executeMethod.Execute(DriverCommand.ExecuteScript, new Dictionary<string, object>
{
["script"] = "mobile:getDisplayDensity",
["args"] = Array.Empty<object>()
}).Value);
executeMethod.Execute(DriverCommand.ExecuteScript, new Dictionary<string, object> {
["script"] = "mobile:getDisplayDensity",
["args"] = Array.Empty<object>()
}).Value);
}

#endregion
Expand Down Expand Up @@ -326,14 +312,14 @@ public static void InstallApp(
}

public static Dictionary<string, object> GetSettings(IExecuteMethod executeMethod) =>
(Dictionary<string, object>)executeMethod.Execute(AppiumDriverCommand.GetSettings).Value;
(Dictionary<string, object>) executeMethod.Execute(AppiumDriverCommand.GetSettings).Value;

public static void SetSetting(IExecuteMethod executeMethod, string setting, object value)
{
var settings = new Dictionary<string, object>()
{ [setting] = value };
{[setting] = value};
var parameters = new Dictionary<string, object>()
{ ["settings"] = settings };
{["settings"] = settings};
executeMethod.Execute(AppiumDriverCommand.UpdateSettings, parameters);
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/Appium.Net/Appium/Android/AndroidDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -493,11 +493,11 @@ public AppState GetAppState(string appId) =>
(AppState)Convert.ToInt32(
ExecuteScript(
"mobile:queryAppState",
[
new object[] {
new Dictionary<string, object>{
["appId"] = appId
}
]
}
)?.ToString() ?? throw new InvalidOperationException("ExecuteScript returned null for mobile:queryAppState")
);

Expand Down
8 changes: 4 additions & 4 deletions src/Appium.Net/Appium/Android/KeyEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public KeyEvent WithKeyCode(int keyCode)
/// <returns></returns>
public KeyEvent WithMetaKeyModifier(int keyEventMetaModifier)
{
_metaState ??= 0;
if (_metaState is null) _metaState = 0;
_metaState |= keyEventMetaModifier;
return this;
}
Expand All @@ -61,7 +61,7 @@ public KeyEvent WithMetaKeyModifier(int keyEventMetaModifier)
/// <returns></returns>
public KeyEvent WithFlag(int flag)
{
_flags ??= 0;
if (_flags is null) _flags = 0;
_flags |= flag;
return this;
}
Expand All @@ -71,8 +71,8 @@ public Dictionary<string, object> Build()
var builder = new Dictionary<string, object>();
if (_keyCode is null) throw new InvalidOperationException("The key code must be set");
builder.Add("keycode", _keyCode);
if (_metaState is not null) builder.Add("metastate", _metaState);
if (_flags is not null) builder.Add("flags", _flags);
if (!(_metaState is null)) builder.Add("metastate", _metaState);
if (!(_flags is null)) builder.Add("flags", _flags);

return builder;
}
Expand Down
Loading
Loading