Skip to content

Commit

Permalink
chore: POC for OpenEdge
Browse files Browse the repository at this point in the history
  • Loading branch information
dtopuzov committed Mar 22, 2022
1 parent c7600eb commit 453c562
Show file tree
Hide file tree
Showing 23 changed files with 690 additions and 1 deletion.
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,15 @@
# win-app-driver-demos
# win-app-driver-demos

WinAppDriver POC with C# and Java.

## Machine Setup

TODO

## Java Demos

TODO

## C# Demos

TODO
52 changes: 52 additions & 0 deletions dotnet/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# EditorConfig is awesome: http://editorconfig.org

# top-most .editorconfig file
root = true

[*]
indent_style = space
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.cs]
indent_size = 4

# CA1816: Call GC.SuppressFinalize correctly
dotnet_diagnostic.CA1816.severity = none

# IDE0005: Remove unnecessary imports
dotnet_diagnostic.IDE0005.severity = warning

# SA0001: XML comment analysis is disabled due to project configuration
dotnet_diagnostic.SA0001.severity = none

# SA0001: XML comment analysis is disabled due to project configuration
dotnet_diagnostic.SA0001.severity = none

# SA1101: Prefix local calls with this
dotnet_diagnostic.SA1101.severity = none

# SA1200: Using directives should be placed correctly
dotnet_diagnostic.SA1200.severity = none

# SA1413: Use trailing comma in multi-line initializers
dotnet_diagnostic.SA1413.severity = none

# SA1600: Elements should be documented
dotnet_diagnostic.SA1600.severity = none

# SA1602: Enumeration items should be documented
dotnet_diagnostic.SA1602.severity = none

# SA1633: File should have header
dotnet_diagnostic.SA1633.severity = none

# CS8602: Dereference of a possibly null reference.
dotnet_diagnostic.CS8602.severity = none

# IDE0090: Use 'new(...)'
dotnet_diagnostic.IDE0090.severity = none

# CS8618: Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
dotnet_diagnostic.CS8618.severity = none
File renamed without changes.
37 changes: 37 additions & 0 deletions dotnet/Framework.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31912.275
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Framework", "Framework\Framework.csproj", "{CEF9E651-4898-4BD7-A9D6-981DA66D86E1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenEdge", "OpenEdge\OpenEdge.csproj", "{6A0B85C9-EA3B-493F-BC86-99E80E98CF43}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{EBED98B8-BECF-49BE-98A5-3931CC316D6E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CEF9E651-4898-4BD7-A9D6-981DA66D86E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CEF9E651-4898-4BD7-A9D6-981DA66D86E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CEF9E651-4898-4BD7-A9D6-981DA66D86E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CEF9E651-4898-4BD7-A9D6-981DA66D86E1}.Release|Any CPU.Build.0 = Release|Any CPU
{6A0B85C9-EA3B-493F-BC86-99E80E98CF43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6A0B85C9-EA3B-493F-BC86-99E80E98CF43}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6A0B85C9-EA3B-493F-BC86-99E80E98CF43}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6A0B85C9-EA3B-493F-BC86-99E80E98CF43}.Release|Any CPU.Build.0 = Release|Any CPU
{EBED98B8-BECF-49BE-98A5-3931CC316D6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EBED98B8-BECF-49BE-98A5-3931CC316D6E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EBED98B8-BECF-49BE-98A5-3931CC316D6E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EBED98B8-BECF-49BE-98A5-3931CC316D6E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7E9BB787-5779-47E8-B8E4-D1DF74114CA6}
EndGlobalSection
EndGlobal
75 changes: 75 additions & 0 deletions dotnet/Framework/App.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using System.Collections.Generic;
using Framework.Settings;
using Framework.Utils;
using Framework.WinAppDriver;
using OpenQA.Selenium;
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.Windows;
using OpenQA.Selenium.Interactions;

namespace Framework
{
public class App
{
public App(AppSettings settings)
{
var options = Client.AppSessionOptions(settings);
Driver = new WindowsDriver<WindowsElement>(Server.Server.ServiceUri, options);
}

public App(AppiumOptions options)
{
Driver = new WindowsDriver<WindowsElement>(Server.Server.ServiceUri, options);
}

public AppiumDriver<WindowsElement> Driver { get; private set; }

public virtual void Stop()
{
if (Driver != null)
{
Driver.Quit();
}
}

public WindowsElement Find(By locator)
{
Wait.Until(() => Driver.FindElements(locator).Count > 0);
return Driver.FindElement(locator);
}

public IReadOnlyCollection<WindowsElement> FindAll(By locator, bool wait = true)
{
if (wait)
{
Wait.Until(() => Driver.FindElements(locator).Count > 0);
}

return Driver.FindElements(locator);
}

public WindowsElement FindByText(string text, bool exactMatch = true)
{
return Find(GetTextLocator(text, exactMatch));
}

public IReadOnlyCollection<WindowsElement> FindAllByText(string text, bool exactMatch = true, bool wait = true)
{
return FindAll(GetTextLocator(text, exactMatch), wait);
}

public void Click(By locator)
{
var element = Find(locator);
var action = new Actions(Driver);
action.MoveToElement(element).Click().Perform();
}

private By GetTextLocator(string text, bool exactMatch = true)
{
return exactMatch
? By.Name(text)
: By.XPath($"//*[contains(@Name,'{text}')]");
}
}
}
74 changes: 74 additions & 0 deletions dotnet/Framework/Desktop.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using System.Collections.Generic;
using Framework.Utils;
using Framework.WinAppDriver;
using OpenQA.Selenium;
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.Windows;

namespace Framework
{
public class Desktop
{
public Desktop()
{
var options = Client.RootSessionOptions();
Driver = new WindowsDriver<WindowsElement>(Server.Server.ServiceUri, options);
}

public AppiumDriver<WindowsElement> Driver { get; private set; }

public void Stop()
{
if (Driver != null)
{
Driver.Quit();
}
}

public App GetAppByTitle(string title)
{
var titleElement = Find(By.Name(title));
var winHandleString = titleElement.GetAttribute("NativeWindowHandle");
var winHandleHex = int.Parse(winHandleString).ToString("x");

var options = new AppiumOptions();
options.AddAdditionalCapability("appTopLevelWindow", winHandleHex);
options.AddAdditionalCapability("deviceName", "WindowsPC");

return new App(options);
}

public WindowsElement Find(By locator)
{
Wait.Until(() => Driver.FindElements(locator).Count > 0);
return Driver.FindElement(locator);
}

public IReadOnlyCollection<WindowsElement> FindAll(By locator, bool wait = true)
{
if (wait)
{
Wait.Until(() => Driver.FindElements(locator).Count > 0);
}

return Driver.FindElements(locator);
}

public WindowsElement FindByText(string text, bool exactMatch = true)
{
return Find(GetTextLocator(text, exactMatch));
}

public IReadOnlyCollection<WindowsElement> FindAllByText(string text, bool exactMatch = true, bool wait = true)
{
return FindAll(GetTextLocator(text, exactMatch), wait);
}

private By GetTextLocator(string text, bool exactMatch = true)
{
return exactMatch
? By.Name(text)
: By.XPath($"//*[contains(@Name,'{text}')]");
}
}
}
17 changes: 17 additions & 0 deletions dotnet/Framework/Framework.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<LangVersion>8.0</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Appium.WebDriver" Version="4.3.1" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

</Project>
11 changes: 11 additions & 0 deletions dotnet/Framework/Settings/AppSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Framework.Settings
{
public class AppSettings
{
public string Path { get; set; }

public string WorkingDirectory { get; set; }

public string Args { get; set; }
}
}
49 changes: 49 additions & 0 deletions dotnet/Framework/Utils/Execute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System;
using System.Diagnostics;

namespace Framework.Utils
{
public static class Execute
{
public static string ExecuteCmd(string command, string workingDirectory, bool waitToFinish = true)
{
var output = string.Empty;
var error = string.Empty;

using (var compiler = new Process())
{
compiler.StartInfo.FileName = "cmd.exe";
compiler.StartInfo.Arguments = $@"/c {command}";
compiler.StartInfo.WorkingDirectory = workingDirectory;
compiler.StartInfo.UseShellExecute = false;
compiler.StartInfo.RedirectStandardOutput = true;
compiler.StartInfo.RedirectStandardError = true;
compiler.Start();

if (waitToFinish)
{
output = compiler.StandardOutput.ReadToEnd();
error = compiler.StandardError.ReadToEnd();
compiler.WaitForExit();
}
}

return error == string.Empty ? output : output + Environment.NewLine + error;
}

public static void PowerShellComand(string arguments)
{
var p = new ProcessStartInfo
{
UseShellExecute = true,
CreateNoWindow = false,
Arguments = arguments,
Verb = "runas",
WindowStyle = ProcessWindowStyle.Hidden,
FileName = "powershell.exe"
};
var proces = Process.Start(p);
proces.WaitForExit();
}
}
}
15 changes: 15 additions & 0 deletions dotnet/Framework/Utils/Processes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Diagnostics;

namespace Framework.Utils
{
public static class Processes
{
public static void KillByName(string processName)
{
foreach (var process in Process.GetProcessesByName(processName))
{
process.Kill();
}
}
}
}
30 changes: 30 additions & 0 deletions dotnet/Framework/Utils/Wait.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System;
using System.Diagnostics;
using System.Threading;

namespace Framework.Utils
{
public class Wait
{
/// <summary>
/// Wait intil function return true or timeout is reached.
/// </summary>
/// <param name="task">Bool function.</param>
/// <param name="timeout">Timeout in seconds.</param>
/// <param name="retryInterval">Deplay between retries in milliseconds.</param>
/// <returns>Result of bool function (false in case timeout reached).</returns>
public static bool Until(Func<bool> task, double timeout = 30, int retryInterval = 100)
{
bool success = false;
TimeSpan maxDuration = TimeSpan.FromSeconds(timeout);
Stopwatch sw = Stopwatch.StartNew();
while (success != true && (sw.Elapsed < maxDuration))
{
Thread.Sleep(retryInterval);
success = task();
}

return success;
}
}
}
Loading

0 comments on commit 453c562

Please sign in to comment.