diff --git a/README.md b/README.md
index ea1a81e1..731fc0eb 100644
--- a/README.md
+++ b/README.md
@@ -33,8 +33,12 @@ Testware provides capabilities to automate:
-
-
+
+- **Websites** (using Selenoid)
+ - Supported Browsers:
+
+
+
- **Mobile Applications** (using Appium)
- **Windows Desktop applications** (using WinAppDriver)
- **API Rest** (using Restsharp)
@@ -155,6 +159,53 @@ Evidence collection:
}
]
},
+ {
+ "Tag": "RemoteDriver",
+ "Capabilities": [
+ {
+ "Name": "Chrome",
+ "Uri": "http://localhost:4444/wd/hub",
+ "BrowserName": "Chrome",
+ "BrowserVersion": "111.0",
+ "Resolution": "1920x1080x24",
+ "EnableLog": false,
+ "EnableVnc": true,
+ "EnableVideo": false,
+ "CommandTimeOutInMinutes": 5,
+ "Arguments": [
+ "--start-maximized"
+ ]
+ },
+ {
+ "Name": "Firefox",
+ "Uri": "http://localhost:4444/wd/hub",
+ "BrowserName": "Firefox",
+ "BrowserVersion": "110.0",
+ "Resolution": "1920x1080x24",
+ "EnableLog": false,
+ "EnableVnc": true,
+ "EnableVideo": false,
+ "CommandTimeOutInMinutes": 5,
+ "Arguments": [
+ "--start-maximized"
+ ]
+ },
+ {
+ "Name": "Edge",
+ "Uri": "http://localhost:4444/wd/hub",
+ "BrowserName": "Edge",
+ "BrowserVersion": "111.0",
+ "Resolution": "1920x1080x24",
+ "EnableLog": false,
+ "EnableVnc": true,
+ "EnableVideo": false,
+ "CommandTimeOutInMinutes": 5,
+ "Arguments": [
+ "--start-maximized"
+ ]
+ }
+ ]
+ },
{
"Name": "Appiumdriver",
"AppiumUrl": "http://127.0.0.1:4723/wd/hub",
diff --git a/TestWare.sln b/TestWare.sln
index ed9de8ba..56ee7b42 100644
--- a/TestWare.sln
+++ b/TestWare.sln
@@ -38,11 +38,17 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestWare.ExtentReport", "sr
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Reporting", "Reporting", "{DCCEF363-0EBE-46EA-B02B-CD59010626F6}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestWare.Engines.Selenoid", "src\Engines\TestWare.Engines.Selenoid\TestWare.Engines.Selenoid.csproj", "{0B7E3DFE-AB55-4C0C-81C6-6A6F517475EE}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestWare.Samples.Selenoid.Web", "samples\TestWare.Samples.Selenoid.Web\TestWare.Samples.Selenoid.Web.csproj", "{672C5D48-DD50-4AA3-8974-50B95746EA07}"
+EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestWare.Engines.MongoDB", "src\Engines\TestWare.Engines.MongoDB\TestWare.Engines.MongoDB.csproj", "{4DFC2BE5-D3EF-4F39-AAD4-B8213DE92A11}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestWare.Samples.MongoDB", "samples\TestWare.Samples.MongoDB\TestWare.Samples.MongoDB.csproj", "{5378DE68-675E-440D-AAA9-7D3AF8AA680E}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestWare.Samples.MongoDB", "samples\TestWare.Samples.MongoDB\TestWare.Samples.MongoDB.csproj", "{5378DE68-675E-440D-AAA9-7D3AF8AA680E}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestWare.AllureReport", "src\Core\TestWare.AllureReport\TestWare.AllureReport.csproj", "{91F2B723-A68B-4711-969B-89897B3C6161}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestWare.AllureReport", "src\Core\TestWare.AllureReport\TestWare.AllureReport.csproj", "{91F2B723-A68B-4711-969B-89897B3C6161}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestWare.Engines.Common", "src\Engines\TestWare.Engines.Common\TestWare.Engines.Common\TestWare.Engines.Common.csproj", "{FFD6A200-D2F1-4CBE-8FDC-320C7839AAB9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -90,6 +96,14 @@ Global
{94025C6B-DF0D-4AC4-BBC5-A94A9FA3AB0A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{94025C6B-DF0D-4AC4-BBC5-A94A9FA3AB0A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{94025C6B-DF0D-4AC4-BBC5-A94A9FA3AB0A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0B7E3DFE-AB55-4C0C-81C6-6A6F517475EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0B7E3DFE-AB55-4C0C-81C6-6A6F517475EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0B7E3DFE-AB55-4C0C-81C6-6A6F517475EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0B7E3DFE-AB55-4C0C-81C6-6A6F517475EE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {672C5D48-DD50-4AA3-8974-50B95746EA07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {672C5D48-DD50-4AA3-8974-50B95746EA07}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {672C5D48-DD50-4AA3-8974-50B95746EA07}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {672C5D48-DD50-4AA3-8974-50B95746EA07}.Release|Any CPU.Build.0 = Release|Any CPU
{4DFC2BE5-D3EF-4F39-AAD4-B8213DE92A11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4DFC2BE5-D3EF-4F39-AAD4-B8213DE92A11}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4DFC2BE5-D3EF-4F39-AAD4-B8213DE92A11}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -102,6 +116,10 @@ Global
{91F2B723-A68B-4711-969B-89897B3C6161}.Debug|Any CPU.Build.0 = Debug|Any CPU
{91F2B723-A68B-4711-969B-89897B3C6161}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91F2B723-A68B-4711-969B-89897B3C6161}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FFD6A200-D2F1-4CBE-8FDC-320C7839AAB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FFD6A200-D2F1-4CBE-8FDC-320C7839AAB9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FFD6A200-D2F1-4CBE-8FDC-320C7839AAB9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FFD6A200-D2F1-4CBE-8FDC-320C7839AAB9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -120,9 +138,12 @@ Global
{71120454-DD7A-484C-93F2-699B4C363297} = {58B1446D-98A3-46A2-A668-305F0170B39F}
{94025C6B-DF0D-4AC4-BBC5-A94A9FA3AB0A} = {DCCEF363-0EBE-46EA-B02B-CD59010626F6}
{DCCEF363-0EBE-46EA-B02B-CD59010626F6} = {4678C707-68DB-4E06-9184-A07FB398832C}
+ {0B7E3DFE-AB55-4C0C-81C6-6A6F517475EE} = {A2E4E1F7-CB61-48DC-AA38-A74F7DC74CA2}
+ {672C5D48-DD50-4AA3-8974-50B95746EA07} = {58B1446D-98A3-46A2-A668-305F0170B39F}
{4DFC2BE5-D3EF-4F39-AAD4-B8213DE92A11} = {A2E4E1F7-CB61-48DC-AA38-A74F7DC74CA2}
{5378DE68-675E-440D-AAA9-7D3AF8AA680E} = {58B1446D-98A3-46A2-A668-305F0170B39F}
{91F2B723-A68B-4711-969B-89897B3C6161} = {DCCEF363-0EBE-46EA-B02B-CD59010626F6}
+ {FFD6A200-D2F1-4CBE-8FDC-320C7839AAB9} = {A2E4E1F7-CB61-48DC-AA38-A74F7DC74CA2}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4F88CB24-23C8-4E0E-8B83-29023C1642B8}
diff --git a/samples/TestWare.Samples.API/TestWare.Samples.API.csproj b/samples/TestWare.Samples.API/TestWare.Samples.API.csproj
index 73379e5a..3dd1aa9f 100644
--- a/samples/TestWare.Samples.API/TestWare.Samples.API.csproj
+++ b/samples/TestWare.Samples.API/TestWare.Samples.API.csproj
@@ -6,13 +6,13 @@
+
-
-
+
-
+
diff --git a/samples/TestWare.Samples.Appium.Mobile/POM/Cart/CartPage.cs b/samples/TestWare.Samples.Appium.Mobile/POM/Cart/CartPage.cs
index 117292ee..1e9bd672 100644
--- a/samples/TestWare.Samples.Appium.Mobile/POM/Cart/CartPage.cs
+++ b/samples/TestWare.Samples.Appium.Mobile/POM/Cart/CartPage.cs
@@ -1,6 +1,6 @@
using OpenQA.Selenium;
using TestWare.Engines.Appium.Pages;
-using TestWare.Engines.Appium.Extras;
+using TestWare.Engines.Common.Extras;
using TestWare.Engines.Appium.Factory;
using TestWare.Core.Libraries;
diff --git a/samples/TestWare.Samples.Appium.Mobile/POM/Login/LoginPage.cs b/samples/TestWare.Samples.Appium.Mobile/POM/Login/LoginPage.cs
index 1ec030bb..d07a842d 100644
--- a/samples/TestWare.Samples.Appium.Mobile/POM/Login/LoginPage.cs
+++ b/samples/TestWare.Samples.Appium.Mobile/POM/Login/LoginPage.cs
@@ -1,5 +1,5 @@
using OpenQA.Selenium;
-using TestWare.Engines.Appium.Extras;
+using TestWare.Engines.Common.Extras;
using TestWare.Engines.Appium.Factory;
using TestWare.Engines.Appium.Pages;
diff --git a/samples/TestWare.Samples.Appium.Mobile/POM/Menu/MenuPage.cs b/samples/TestWare.Samples.Appium.Mobile/POM/Menu/MenuPage.cs
index 3a5a060b..dd3d687b 100644
--- a/samples/TestWare.Samples.Appium.Mobile/POM/Menu/MenuPage.cs
+++ b/samples/TestWare.Samples.Appium.Mobile/POM/Menu/MenuPage.cs
@@ -1,6 +1,6 @@
using OpenQA.Selenium;
using TestWare.Engines.Appium.Pages;
-using TestWare.Engines.Appium.Extras;
+using TestWare.Engines.Common.Extras;
using TestWare.Engines.Appium.Factory;
namespace TestWare.Samples.Appium.Mobile.POM.Menu;
diff --git a/samples/TestWare.Samples.Appium.Mobile/POM/Product/ProductPage.cs b/samples/TestWare.Samples.Appium.Mobile/POM/Product/ProductPage.cs
index 8e018e54..a81fdfc2 100644
--- a/samples/TestWare.Samples.Appium.Mobile/POM/Product/ProductPage.cs
+++ b/samples/TestWare.Samples.Appium.Mobile/POM/Product/ProductPage.cs
@@ -1,7 +1,7 @@
using OpenQA.Selenium;
using OpenQA.Selenium.Appium;
using TestWare.Core.Libraries;
-using TestWare.Engines.Appium.Extras;
+using TestWare.Engines.Common.Extras;
using TestWare.Engines.Appium.Factory;
using TestWare.Engines.Appium.Pages;
diff --git a/samples/TestWare.Samples.Appium.Mobile/TestWare.Samples.Appium.Mobile.csproj b/samples/TestWare.Samples.Appium.Mobile/TestWare.Samples.Appium.Mobile.csproj
index 59c4be80..12be5a98 100644
--- a/samples/TestWare.Samples.Appium.Mobile/TestWare.Samples.Appium.Mobile.csproj
+++ b/samples/TestWare.Samples.Appium.Mobile/TestWare.Samples.Appium.Mobile.csproj
@@ -7,12 +7,12 @@
+
-
-
+
-
+
diff --git a/samples/TestWare.Samples.MongoDB/TestWare.Samples.MongoDB.csproj b/samples/TestWare.Samples.MongoDB/TestWare.Samples.MongoDB.csproj
index 5f7c44b4..4319e2de 100644
--- a/samples/TestWare.Samples.MongoDB/TestWare.Samples.MongoDB.csproj
+++ b/samples/TestWare.Samples.MongoDB/TestWare.Samples.MongoDB.csproj
@@ -9,7 +9,7 @@
-
+
diff --git a/samples/TestWare.Samples.Selenium.Web/POM/Stinto/Chat/ChatPage.cs b/samples/TestWare.Samples.Selenium.Web/POM/Stinto/Chat/ChatPage.cs
index cfed90a4..a2646dbf 100644
--- a/samples/TestWare.Samples.Selenium.Web/POM/Stinto/Chat/ChatPage.cs
+++ b/samples/TestWare.Samples.Selenium.Web/POM/Stinto/Chat/ChatPage.cs
@@ -1,6 +1,6 @@
using OpenQA.Selenium;
using TestWare.Core.Libraries;
-using TestWare.Engines.Selenium.Extras;
+using TestWare.Engines.Common.Extras;
using TestWare.Engines.Selenium.Factory;
using TestWare.Engines.Selenium.Pages;
diff --git a/samples/TestWare.Samples.Selenium.Web/POM/Stinto/CreateChat/CreateChatPage.cs b/samples/TestWare.Samples.Selenium.Web/POM/Stinto/CreateChat/CreateChatPage.cs
index 2b788a26..8f9c02c1 100644
--- a/samples/TestWare.Samples.Selenium.Web/POM/Stinto/CreateChat/CreateChatPage.cs
+++ b/samples/TestWare.Samples.Selenium.Web/POM/Stinto/CreateChat/CreateChatPage.cs
@@ -1,5 +1,5 @@
using OpenQA.Selenium;
-using TestWare.Engines.Selenium.Extras;
+using TestWare.Engines.Common.Extras;
using TestWare.Engines.Selenium.Factory;
using TestWare.Engines.Selenium.Pages;
diff --git a/samples/TestWare.Samples.Selenium.Web/POM/Stinto/Home/HomePage.cs b/samples/TestWare.Samples.Selenium.Web/POM/Stinto/Home/HomePage.cs
index 9fb3e451..38ddb933 100644
--- a/samples/TestWare.Samples.Selenium.Web/POM/Stinto/Home/HomePage.cs
+++ b/samples/TestWare.Samples.Selenium.Web/POM/Stinto/Home/HomePage.cs
@@ -1,5 +1,5 @@
using OpenQA.Selenium;
-using TestWare.Engines.Selenium.Extras;
+using TestWare.Engines.Common.Extras;
using TestWare.Engines.Selenium.Factory;
using TestWare.Engines.Selenium.Pages;
diff --git a/samples/TestWare.Samples.Selenium.Web/POM/SwagLabs/Login/LoginPage.cs b/samples/TestWare.Samples.Selenium.Web/POM/SwagLabs/Login/LoginPage.cs
index 82547164..8b1b1dc6 100644
--- a/samples/TestWare.Samples.Selenium.Web/POM/SwagLabs/Login/LoginPage.cs
+++ b/samples/TestWare.Samples.Selenium.Web/POM/SwagLabs/Login/LoginPage.cs
@@ -1,6 +1,6 @@
using OpenQA.Selenium;
using TestWare.Core.Libraries;
-using TestWare.Engines.Selenium.Extras;
+using TestWare.Engines.Common.Extras;
using TestWare.Engines.Selenium.Factory;
using TestWare.Engines.Selenium.Pages;
diff --git a/samples/TestWare.Samples.Selenium.Web/POM/SwagLabs/Menu/MenuPage.cs b/samples/TestWare.Samples.Selenium.Web/POM/SwagLabs/Menu/MenuPage.cs
index 715dab7d..dc246ee6 100644
--- a/samples/TestWare.Samples.Selenium.Web/POM/SwagLabs/Menu/MenuPage.cs
+++ b/samples/TestWare.Samples.Selenium.Web/POM/SwagLabs/Menu/MenuPage.cs
@@ -1,5 +1,5 @@
using OpenQA.Selenium;
-using TestWare.Engines.Selenium.Extras;
+using TestWare.Engines.Common.Extras;
using TestWare.Engines.Selenium.Factory;
using TestWare.Engines.Selenium.Pages;
diff --git a/samples/TestWare.Samples.Selenium.Web/TestWare.Samples.Selenium.Web.csproj b/samples/TestWare.Samples.Selenium.Web/TestWare.Samples.Selenium.Web.csproj
index de40c02e..43cf4bdb 100644
--- a/samples/TestWare.Samples.Selenium.Web/TestWare.Samples.Selenium.Web.csproj
+++ b/samples/TestWare.Samples.Selenium.Web/TestWare.Samples.Selenium.Web.csproj
@@ -19,13 +19,13 @@
+
-
-
-
+
+
diff --git a/samples/TestWare.Samples.Selenoid.Web/Features/SwagLabs/Login.feature b/samples/TestWare.Samples.Selenoid.Web/Features/SwagLabs/Login.feature
new file mode 100644
index 00000000..4ac466ba
--- /dev/null
+++ b/samples/TestWare.Samples.Selenoid.Web/Features/SwagLabs/Login.feature
@@ -0,0 +1,32 @@
+@RemoteDriver
+Feature: Login
+
+Scenario Outline: Login
+ Given the user enters username ''
+ And the user enters password ''
+ When the user clicks submit
+ Then the user can login
+
+ @Chrome
+ Examples:
+ | Example Description | username | password |
+ | standard | standard_user | secret_sauce |
+ | problem | problem_user | secret_sauce |
+
+ @Firefox
+ Examples:
+ | Example Description | username | password |
+ | standard | standard_user | secret_sauce |
+ | problem | problem_user | secret_sauce |
+
+ @Edge
+ Examples:
+ | Example Description | username | password |
+ | standard | standard_user | secret_sauce |
+ | problem | problem_user | secret_sauce |
+
+@Chrome
+Scenario: Logout
+ Given user 'standard_user' is logged with 'secret_sauce' into SwagLabs
+ When the user clicks Logout button
+ Then the user is at Login page
diff --git a/samples/TestWare.Samples.Selenoid.Web/Hook.cs b/samples/TestWare.Samples.Selenoid.Web/Hook.cs
new file mode 100644
index 00000000..742d855d
--- /dev/null
+++ b/samples/TestWare.Samples.Selenoid.Web/Hook.cs
@@ -0,0 +1,110 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using TestWare.Reporting.ExtentReport;
+
+namespace TestWare.Samples.Selenoid.Web;
+
+[Binding]
+public sealed class Hook
+{
+ private readonly TestContext _testContext;
+ private int _stepCounter;
+ private static readonly LifeCycle _lifeCycle = new();
+ private static ExtentReport _testReport;
+
+ public Hook(TestContext testContext)
+ {
+ _testContext = testContext;
+ }
+
+ [BeforeFeature]
+ public static void BeforeFeature(FeatureContext featureContext)
+ {
+ var name = featureContext.FeatureInfo.Title;
+ var tags = featureContext.FeatureInfo.Tags;
+
+ _lifeCycle.BeginTestSuite(name);
+ _testReport.CreateFeature(name, tags);
+ }
+
+ [AfterFeature]
+ public static void AfterFeature(FeatureContext featureContext)
+ {
+ _lifeCycle.EndTestSuite();
+ }
+
+ [BeforeScenario]
+ public void BeforeScenario(FeatureContext featureContext, ScenarioContext scenarioContext)
+ {
+ var name = scenarioContext.ScenarioInfo.Arguments.Count > 0
+ ? $"{DateTime.UtcNow.ToString("yyy-MM-dd HH-mm-ss", CultureInfo.InvariantCulture)} - {scenarioContext.ScenarioInfo.Title}"
+ : scenarioContext.ScenarioInfo.Title;
+
+ var description = scenarioContext.ScenarioInfo.Description ?? "";
+ var scenarioTags = scenarioContext.ScenarioInfo.Tags;
+ _testReport.CreateTestCase(name, description, scenarioTags);
+
+ _testContext.WriteLine("----------------------------------------- \r\n");
+ _testContext.WriteLine($"Feature: {featureContext.FeatureInfo.Title}");
+ _testContext.WriteLine($" Scenario: {scenarioContext.ScenarioInfo.Title} \r\n");
+
+ _stepCounter = 1;
+ var tags = GetTags(featureContext, scenarioContext);
+ _lifeCycle.BeginTestCase(name, tags);
+ }
+
+ [AfterScenario]
+ public void AfterScenario()
+ {
+ _testReport.SetTestcaseOutcome(_testContext.CurrentTestOutcome);
+ _lifeCycle.EndTestCase();
+ }
+
+ [BeforeTestRun]
+ public static void BeforeTestRun()
+ {
+ _lifeCycle.BeginTestExecution();
+ _testReport = new ExtentReport(_lifeCycle.GetCurrentResultsDirectory());
+ }
+
+ [AfterTestRun]
+ public static void AfterTestRun()
+ {
+ _lifeCycle.EndTestExecution();
+ _testReport.CreateTestReportFile();
+ }
+
+ [BeforeStep]
+ public void BeforeStep(ScenarioContext scenarioContext)
+ {
+ var name = scenarioContext.CurrentScenarioBlock.ToString();
+ var description = scenarioContext.StepContext.StepInfo.Text;
+ _testReport.CreateStep(name, description);
+
+ var stepId = $"{_stepCounter:00} {description}";
+ _stepCounter++;
+ _lifeCycle.BeginTestStep(stepId);
+ }
+
+ [AfterStep]
+ public void AfterStep(ScenarioContext scenarioContext)
+ {
+ _lifeCycle.EndTestStep();
+ var evidencesPath = _lifeCycle.GetStepEvidences();
+
+ foreach (var evidence in evidencesPath)
+ {
+ _testReport.AddScreenshotToStep(evidence);
+ _testContext.AddResultFile(evidence);
+ }
+ }
+
+ private static List GetTags(FeatureContext featureContext, ScenarioContext scenarioContext)
+ {
+ var tags = featureContext.FeatureInfo.Tags.ToList();
+ tags.AddRange(scenarioContext.ScenarioInfo.Tags.ToList());
+ return tags;
+ }
+}
diff --git a/samples/TestWare.Samples.Selenoid.Web/ImplicitUsings.cs b/samples/TestWare.Samples.Selenoid.Web/ImplicitUsings.cs
new file mode 100644
index 00000000..26bc47f3
--- /dev/null
+++ b/samples/TestWare.Samples.Selenoid.Web/ImplicitUsings.cs
@@ -0,0 +1,3 @@
+global using FluentAssertions;
+global using Microsoft.VisualStudio.TestTools.UnitTesting;
+global using TechTalk.SpecFlow;
diff --git a/samples/TestWare.Samples.Selenoid.Web/LifeCycle.cs b/samples/TestWare.Samples.Selenoid.Web/LifeCycle.cs
new file mode 100644
index 00000000..ed161129
--- /dev/null
+++ b/samples/TestWare.Samples.Selenoid.Web/LifeCycle.cs
@@ -0,0 +1,36 @@
+using System.Collections.Generic;
+using System.Reflection;
+using TestWare.Core;
+using TestWare.Core.Configuration;
+using TestWare.Core.Interfaces;
+using TestWare.Engines.Selenoid;
+
+namespace TestWare.Samples.Selenoid.Web;
+
+internal class LifeCycle : AutomationLifeCycleBase
+{
+ protected override IEnumerable GetTestWareComponentAssemblies()
+ {
+ IEnumerable assemblies = new[]
+ {
+ typeof(Hook).Assembly
+ };
+
+ return assemblies;
+ }
+
+ protected override IEnumerable GetTestWareEngines()
+ {
+ IEnumerable engines = new[]
+ {
+ new SelenoidManager()
+ };
+
+ return engines;
+ }
+
+ protected override TestConfiguration GetConfiguration()
+ {
+ return ConfigurationManager.ReadConfigurationFile("TestConfiguration.Web.json");
+ }
+}
diff --git a/samples/TestWare.Samples.Selenoid.Web/POM/SwagLabs/Inventory/IInventoryPage.cs b/samples/TestWare.Samples.Selenoid.Web/POM/SwagLabs/Inventory/IInventoryPage.cs
new file mode 100644
index 00000000..7cfcdb44
--- /dev/null
+++ b/samples/TestWare.Samples.Selenoid.Web/POM/SwagLabs/Inventory/IInventoryPage.cs
@@ -0,0 +1,9 @@
+using TestWare.Core.Interfaces;
+
+namespace TestWare.Samples.Selenoid.Web.POM.Inventory;
+
+public interface IInventoryPage : ITestWareComponent
+{
+ void CheckUserIsAtInventory();
+}
+
diff --git a/samples/TestWare.Samples.Selenoid.Web/POM/SwagLabs/Inventory/InventoryPage.cs b/samples/TestWare.Samples.Selenoid.Web/POM/SwagLabs/Inventory/InventoryPage.cs
new file mode 100644
index 00000000..54260bd1
--- /dev/null
+++ b/samples/TestWare.Samples.Selenoid.Web/POM/SwagLabs/Inventory/InventoryPage.cs
@@ -0,0 +1,27 @@
+using OpenQA.Selenium;
+using TestWare.Core.Libraries;
+using TestWare.Engines.Selenoid.Factory;
+using TestWare.Engines.Selenoid.Pages;
+
+namespace TestWare.Samples.Selenoid.Web.POM.Inventory;
+
+public class InventoryPage : WebPage, IInventoryPage
+{
+ private const string InventoryUrl = "https://www.saucedemo.com/inventory.html";
+
+ public InventoryPage(IWebDriver driver) : base(driver)
+ {
+ }
+
+ ///
+ public void CheckUserIsAtInventory()
+ {
+ RetryPolicies.ExecuteActionWithRetries(
+ () =>
+ {
+ this.Driver.Url.Should().Be(InventoryUrl);
+ });
+ }
+
+}
+
diff --git a/samples/TestWare.Samples.Selenoid.Web/POM/SwagLabs/Login/ILoginPage.cs b/samples/TestWare.Samples.Selenoid.Web/POM/SwagLabs/Login/ILoginPage.cs
new file mode 100644
index 00000000..49d6c09c
--- /dev/null
+++ b/samples/TestWare.Samples.Selenoid.Web/POM/SwagLabs/Login/ILoginPage.cs
@@ -0,0 +1,31 @@
+using TestWare.Core.Interfaces;
+
+namespace TestWare.Samples.Selenoid.Web.POM.Login;
+
+///
+/// Encapsulate all Loging busines logic
+///
+public interface ILoginPage : ITestWareComponent
+{
+ ///
+ /// Script to send User Name
+ ///
+ ///
+ void EnterUserName(string name);
+
+ ///
+ /// Script to send User Password
+ ///
+ ///
+ void EnterUserPassword(string password);
+
+ ///
+ /// Click in Login button
+ ///
+ void ClickLoginButton();
+
+ ///
+ /// Check that the user is at Login Page
+ ///
+ void CheckUserIsAtLoginpage();
+}
diff --git a/samples/TestWare.Samples.Selenoid.Web/POM/SwagLabs/Login/LoginPage.cs b/samples/TestWare.Samples.Selenoid.Web/POM/SwagLabs/Login/LoginPage.cs
new file mode 100644
index 00000000..e5eceb6d
--- /dev/null
+++ b/samples/TestWare.Samples.Selenoid.Web/POM/SwagLabs/Login/LoginPage.cs
@@ -0,0 +1,54 @@
+using OpenQA.Selenium;
+using TestWare.Core.Libraries;
+using TestWare.Engines.Common.Extras;
+using TestWare.Engines.Selenoid.Factory;
+using TestWare.Engines.Selenoid.Pages;
+
+namespace TestWare.Samples.Selenoid.Web.POM.Login;
+
+public class LoginPage : WebPage, ILoginPage
+{
+ private const string LoginUrl = "https://www.saucedemo.com/";
+
+ [FindsBy(How = How.Name, Using = "user-name")]
+ private IWebElement UserIdTextBox { get; set; }
+
+ [FindsBy(How = How.Name, Using = "password")]
+ private IWebElement UserPasswordTextBox { get; set; }
+
+ [FindsBy(How = How.Name, Using = "login-button")]
+ private IWebElement LoginButton { get; set; }
+
+ public LoginPage(IWebDriver driver) : base(driver)
+ {
+ Url = LoginUrl;
+ NavigateToUrl();
+ }
+
+ ///
+ public void EnterUserName(string name)
+ => SendKeysElement(UserIdTextBox, name);
+
+ ///
+ public void ConfirmLogoutPopup()
+ => this.Driver.SwitchTo().Alert().Accept();
+
+ ///
+ public void EnterUserPassword(string password)
+ => SendKeysElement(UserPasswordTextBox, password);
+
+ ///
+
+ public void ClickLoginButton()
+ => ClickElement(LoginButton);
+
+ ///
+ public void CheckUserIsAtLoginpage()
+ {
+ RetryPolicies.ExecuteActionWithRetries(
+ () =>
+ {
+ this.Driver.Url.Should().Be(LoginUrl);
+ });
+ }
+}
diff --git a/samples/TestWare.Samples.Selenoid.Web/POM/SwagLabs/Menu/IMenuPage.cs b/samples/TestWare.Samples.Selenoid.Web/POM/SwagLabs/Menu/IMenuPage.cs
new file mode 100644
index 00000000..6d145167
--- /dev/null
+++ b/samples/TestWare.Samples.Selenoid.Web/POM/SwagLabs/Menu/IMenuPage.cs
@@ -0,0 +1,13 @@
+using TestWare.Core.Interfaces;
+
+namespace TestWare.Samples.Selenoid.Web.POM.Menu;
+
+///
+/// Initializes a new instance of the interface class that contains
+/// all the methods that can be used at Steps level.
+///
+public interface IMenuPage : ITestWareComponent
+{
+ void ClickLogoutButton();
+ void ClickOpenMenuButton();
+}
diff --git a/samples/TestWare.Samples.Selenoid.Web/POM/SwagLabs/Menu/MenuPage.cs b/samples/TestWare.Samples.Selenoid.Web/POM/SwagLabs/Menu/MenuPage.cs
new file mode 100644
index 00000000..3c953f28
--- /dev/null
+++ b/samples/TestWare.Samples.Selenoid.Web/POM/SwagLabs/Menu/MenuPage.cs
@@ -0,0 +1,30 @@
+using OpenQA.Selenium;
+using TestWare.Engines.Common.Extras;
+using TestWare.Engines.Selenoid.Factory;
+using TestWare.Engines.Selenoid.Pages;
+
+namespace TestWare.Samples.Selenoid.Web.POM.Menu;
+
+///
+/// Initializes a new instance of the class that contains
+/// all the elements and the interaction methods that will be exposed at it's Interface class.
+///
+public class MenuPage : WebPage, IMenuPage
+{
+ [FindsBy(How = How.Id, Using = "react-burger-menu-btn")]
+ private IWebElement OpenMenuButton { get; set; }
+
+ [FindsBy(How = How.Id, Using = "logout_sidebar_link")]
+ private IWebElement LogoutButton { get; set; }
+
+ public MenuPage(IWebDriver driver)
+ : base(driver)
+ {
+ }
+
+ public void ClickOpenMenuButton()
+ => ClickElement(OpenMenuButton);
+
+ public void ClickLogoutButton()
+ => ClickElement(LogoutButton);
+}
diff --git a/samples/TestWare.Samples.Selenoid.Web/Selenoid/browsers.json b/samples/TestWare.Samples.Selenoid.Web/Selenoid/browsers.json
new file mode 100644
index 00000000..c4fb8d4c
--- /dev/null
+++ b/samples/TestWare.Samples.Selenoid.Web/Selenoid/browsers.json
@@ -0,0 +1,65 @@
+{
+ "chrome": {
+ "default": "111.0",
+ "versions": {
+ "111.0": {
+ "image": "selenoid/chrome:111.0",
+ "port": "4444",
+ "volumes": ["/c/temp/downloads:/home/selenium/Downloads"],
+ "path": "/",
+ "tmpfs": {
+ "/tmp": "size=128m"
+ }
+ },
+ "94.0": {
+ "image": "selenoid/chrome:94.0",
+ "port": "4444",
+ "volumes": ["/c/temp/downloads:/home/selenium/Downloads"],
+ "path": "/",
+ "tmpfs": {
+ "/tmp": "size=128m"
+ }
+ }
+ }
+ },
+ "firefox": {
+ "default": "110.0",
+ "versions": {
+ "110.0": {
+ "image": "selenoid/firefox:110.0",
+ "port": "4444",
+ "volumes": ["/c/temp/downloads:/home/selenium/Downloads"],
+ "path": "/wd/hub",
+ "tmpfs": {
+ "/tmp": "size=128m"
+ }
+ },
+ "92.0": {
+ "image": "selenoid/firefox:92.0",
+ "port": "4444",
+ "volumes": ["/c/temp/downloads:/home/selenium/Downloads"],
+ "path": "/wd/hub",
+ "tmpfs": {
+ "/tmp": "size=128m"
+ }
+ }
+ }
+ },
+ "MicrosoftEdge": {
+ "default": "111.0",
+ "versions": {
+ "111.0": {
+ "image": "browsers/edge:111.0",
+ "port": "4444",
+ "volumes": ["/c/temp/downloads:/home/selenium/Downloads"],
+ "path": "/"
+ },
+ "94.0": {
+ "image": "browsers/edge:94.0",
+ "port": "4444",
+ "volumes": ["/c/temp/downloads:/home/selenium/Downloads"],
+ "path": "/"
+ }
+ }
+ }
+}
diff --git a/samples/TestWare.Samples.Selenoid.Web/Selenoid/docker-compose.yml b/samples/TestWare.Samples.Selenoid.Web/Selenoid/docker-compose.yml
new file mode 100644
index 00000000..9daccaf3
--- /dev/null
+++ b/samples/TestWare.Samples.Selenoid.Web/Selenoid/docker-compose.yml
@@ -0,0 +1,28 @@
+version: '3'
+services:
+ selenoid:
+ restart: always
+ network_mode: bridge
+ image: aerokube/selenoid:latest-release
+ volumes:
+ - ".:/etc/selenoid"
+ - "/var/run/docker.sock:/var/run/docker.sock"
+ - "./video:/opt/selenoid/video"
+ - "./logs:/opt/selenoid/logs"
+ environment:
+ - OVERRIDE_VIDEO_OUTPUT_DIR=./logs
+ command: ["-conf", "/etc/selenoid/browsers.json", "-video-output-dir", "/opt/selenoid/video", "-log-output-dir", "/opt/selenoid/logs"]
+ ports:
+ - "4444:4444"
+
+ selenoid-ui:
+ restart: always
+ image: "aerokube/selenoid-ui:latest-release"
+ network_mode: bridge
+ depends_on:
+ - selenoid
+ links:
+ - selenoid
+ ports:
+ - "8888:8080"
+ command: ["--selenoid-uri", "http://selenoid:4444"]
\ No newline at end of file
diff --git a/samples/TestWare.Samples.Selenoid.Web/Selenoid/start-selenoid-docker.ps1 b/samples/TestWare.Samples.Selenoid.Web/Selenoid/start-selenoid-docker.ps1
new file mode 100644
index 00000000..ef53fd45
--- /dev/null
+++ b/samples/TestWare.Samples.Selenoid.Web/Selenoid/start-selenoid-docker.ps1
@@ -0,0 +1,13 @@
+Write-Host "Stopping selenoid and selenoid-ui containers" -ForegroundColor DarkGreen
+docker-compose down
+
+Write-Host "Downloading browser images...." -ForegroundColor DarkGreen
+$browsers = Get-Content .\browsers.json | ConvertFrom-Json
+foreach($browser in $browsers.PsObject.Properties.Value) {
+ foreach($version in $browser.versions.PsObject.Properties.Value) {
+ docker pull $version.image
+ }
+}
+
+Write-Host "Starting selenoid and selenoid-ui containers" -ForegroundColor DarkGreen
+docker-compose up -d
\ No newline at end of file
diff --git a/samples/TestWare.Samples.Selenoid.Web/StepDefinitions/SwagLabs/InventorySteps.cs b/samples/TestWare.Samples.Selenoid.Web/StepDefinitions/SwagLabs/InventorySteps.cs
new file mode 100644
index 00000000..18f44adf
--- /dev/null
+++ b/samples/TestWare.Samples.Selenoid.Web/StepDefinitions/SwagLabs/InventorySteps.cs
@@ -0,0 +1,25 @@
+using TestWare.Core;
+using TestWare.Samples.Selenoid.Web.POM.Inventory;
+
+namespace TestWare.Samples.Selenoid.Web.StepDefinitions;
+
+///
+/// Initializes a new instance of the class that contains
+/// all the step action methods that can be used at Feature level.
+///
+[Binding]
+public sealed class InventorySteps
+{
+ private readonly IInventoryPage inventoryPage;
+
+ public InventorySteps()
+ {
+ inventoryPage = ContainerManager.GetTestWareComponent();
+ }
+
+ [Then(@"the user can login")]
+ public void ThenTheUserCanLogin()
+ {
+ inventoryPage.CheckUserIsAtInventory();
+ }
+}
diff --git a/samples/TestWare.Samples.Selenoid.Web/StepDefinitions/SwagLabs/LoginSteps.cs b/samples/TestWare.Samples.Selenoid.Web/StepDefinitions/SwagLabs/LoginSteps.cs
new file mode 100644
index 00000000..c43b759d
--- /dev/null
+++ b/samples/TestWare.Samples.Selenoid.Web/StepDefinitions/SwagLabs/LoginSteps.cs
@@ -0,0 +1,53 @@
+using TestWare.Core;
+using TestWare.Samples.Selenoid.Web.POM.Login;
+
+namespace TestWare.Samples.Selenoid.Web.StepDefinitions;
+
+///
+/// Initializes a new instance of the class that contains
+/// all the step action methods that can be used at Feature level.
+///
+[Binding]
+public sealed class LoginSteps
+{
+ private readonly ILoginPage loginPage;
+
+ public LoginSteps()
+ {
+ loginPage = ContainerManager.GetTestWareComponent();
+ }
+
+ [Given(@"the user enters username '([^']*)'")]
+ public void GivenTheUserEntersUsername(string userName)
+ {
+ loginPage.EnterUserName(userName);
+ }
+
+ [Given(@"the user enters password '([^']*)'")]
+ public void GivenTheUserEntersValidPassword(string password)
+ {
+ loginPage.EnterUserPassword(password);
+ }
+
+ [Given(@"user '([^']*)' is logged with '([^']*)' into SwagLabs")]
+ public void GivenUserIsLogedWithIntoSwagLabs(string userName, string password)
+ {
+ GivenTheUserEntersUsername(userName);
+ GivenTheUserEntersValidPassword(password);
+ WhenTheUserClicksSubmit();
+ }
+
+
+ [Given(@"the user clicks submit")]
+ [When(@"the user clicks submit")]
+ public void WhenTheUserClicksSubmit()
+ {
+ loginPage.ClickLoginButton();
+ }
+
+ [Then(@"the user is at Login page")]
+ public void UserIsAtLoginPage()
+ {
+ loginPage.CheckUserIsAtLoginpage();
+ }
+}
diff --git a/samples/TestWare.Samples.Selenoid.Web/StepDefinitions/SwagLabs/MenuSteps.cs b/samples/TestWare.Samples.Selenoid.Web/StepDefinitions/SwagLabs/MenuSteps.cs
new file mode 100644
index 00000000..492ec89a
--- /dev/null
+++ b/samples/TestWare.Samples.Selenoid.Web/StepDefinitions/SwagLabs/MenuSteps.cs
@@ -0,0 +1,26 @@
+using TestWare.Core;
+using TestWare.Samples.Selenoid.Web.POM.Menu;
+
+namespace TestWare.Samples.Selenoid.Web.StepDefinitions;
+
+///
+/// Initializes a new instance of the class that contains
+/// all the step action methods that can be used at Feature level.
+///
+[Binding]
+public sealed class MenuSteps
+{
+ private readonly IMenuPage menuPage;
+
+ public MenuSteps()
+ {
+ menuPage = ContainerManager.GetTestWareComponent();
+ }
+
+ [When(@"the user clicks Logout button")]
+ public void WhenTheUserClicksLogoutButton()
+ {
+ menuPage.ClickOpenMenuButton();
+ menuPage.ClickLogoutButton();
+ }
+}
diff --git a/samples/TestWare.Samples.Selenoid.Web/StepDefinitions/SwagLabs/MultiplePageSteps.cs b/samples/TestWare.Samples.Selenoid.Web/StepDefinitions/SwagLabs/MultiplePageSteps.cs
new file mode 100644
index 00000000..35fd511e
--- /dev/null
+++ b/samples/TestWare.Samples.Selenoid.Web/StepDefinitions/SwagLabs/MultiplePageSteps.cs
@@ -0,0 +1,67 @@
+using System.Collections.Generic;
+using System.Linq;
+using TestWare.Core;
+using TestWare.Samples.Selenoid.Web.POM.Inventory;
+using TestWare.Samples.Selenoid.Web.POM.Login;
+using TestWare.Samples.Selenoid.Web.POM.Menu;
+
+namespace TestWare.Samples.Selenoid.Web.StepDefinitions;
+
+///
+/// Initializes a new instance of the class that contains
+/// all the step action methods that can be used at Feature level.
+///
+[Binding]
+public sealed class MultiplePageSteps
+{
+ private readonly IEnumerable loginPages;
+ private readonly IEnumerable inventoryPages;
+
+ public MultiplePageSteps(FeatureContext featureContext, ScenarioContext scenarioContext)
+ {
+ var tags = featureContext.FeatureInfo.Tags.Concat(scenarioContext.ScenarioInfo.Tags);
+ loginPages = ContainerManager.GetTestWareComponents(tags);
+ inventoryPages = ContainerManager.GetTestWareComponents(tags);
+ }
+
+ [Given(@"the user enters username '([^']*)' on all")]
+ public void GivenTheUserEntersUsernameOnAll(string userName)
+ {
+ loginPages.ToList().ForEach(x => x.EnterUserName(userName));
+ }
+
+ [Given(@"the user enters password '([^']*)' on all")]
+ public void GivenTheUserEntersValidPasswordOnAll(string password)
+ {
+ loginPages.ToList().ForEach(x => x.EnterUserPassword(password));
+ }
+
+ [Given(@"the user clicks submit on all")]
+ [When(@"the user clicks submit on all")]
+ public void WhenTheUserClicksSubmitOnAll()
+ {
+ loginPages.ToList().ForEach(x => x.ClickLoginButton());
+ }
+
+ [Given(@"the user can login on all")]
+ [Then(@"the user can login on all")]
+ public void ThenTheUserCanLoginOnAll()
+ {
+ inventoryPages.ToList().ForEach(x => x.CheckUserIsAtInventory());
+ }
+
+ [When(@"the user clicks Logout button on '([^']*)'")]
+ public static void WhenTheUserClicksLogoutButtonOn(string browser)
+ {
+ var menuPage = ContainerManager.GetTestWareComponent(browser);
+ menuPage.ClickOpenMenuButton();
+ menuPage.ClickLogoutButton();
+ }
+
+ [Then(@"the user is at Login page on '([^']*)'")]
+ public static void ThenTheUserIsAtLoginPageOn(string browser)
+ {
+ var loginPage = ContainerManager.GetTestWareComponent(browser);
+ loginPage.CheckUserIsAtLoginpage();
+ }
+}
diff --git a/samples/TestWare.Samples.Selenoid.Web/TestConfiguration.Web.json b/samples/TestWare.Samples.Selenoid.Web/TestConfiguration.Web.json
new file mode 100644
index 00000000..d96ad277
--- /dev/null
+++ b/samples/TestWare.Samples.Selenoid.Web/TestConfiguration.Web.json
@@ -0,0 +1,52 @@
+{
+ "Configurations": [
+ {
+ "Tag": "RemoteDriver",
+ "Capabilities": [
+ {
+ "Name": "Chrome",
+ "Uri": "http://localhost:4444/wd/hub",
+ "BrowserName": "Chrome",
+ "BrowserVersion": "111.0",
+ "Resolution": "1920x1080x24",
+ "EnableLog": false,
+ "EnableVnc": true,
+ "EnableVideo": false,
+ "CommandTimeOutInMinutes": 5,
+ "Arguments": [
+ "--start-maximized"
+ ]
+ },
+ {
+ "Name": "Firefox",
+ "Uri": "http://localhost:4444/wd/hub",
+ "BrowserName": "Firefox",
+ "BrowserVersion": "110.0",
+ "Resolution": "1920x1080x24",
+ "EnableLog": false,
+ "EnableVnc": true,
+ "EnableVideo": false,
+ "CommandTimeOutInMinutes": 5,
+ "Arguments": [
+ "--start-maximized"
+ ]
+ },
+ {
+ "Name": "Edge",
+ "Uri": "http://localhost:4444/wd/hub",
+ "BrowserName": "Edge",
+ "BrowserVersion": "111.0",
+ "Resolution": "1920x1080x24",
+ "EnableLog": false,
+ "EnableVnc": true,
+ "EnableVideo": false,
+ "CommandTimeOutInMinutes": 5,
+ "Arguments": [
+ "--start-maximized"
+ ]
+ }
+ ]
+ }
+ ],
+ "TestResultPath": "C:\\workspace\\ERNI\\results\\"
+}
\ No newline at end of file
diff --git a/samples/TestWare.Samples.Selenoid.Web/TestWare.Samples.Selenoid.Web.csproj b/samples/TestWare.Samples.Selenoid.Web/TestWare.Samples.Selenoid.Web.csproj
new file mode 100644
index 00000000..26ee5272
--- /dev/null
+++ b/samples/TestWare.Samples.Selenoid.Web/TestWare.Samples.Selenoid.Web.csproj
@@ -0,0 +1,31 @@
+
+
+
+ net6.0
+ enable
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Always
+
+
+
+
diff --git a/samples/TestWare.Samples.WinAppDriver/POM/Calculator/CalculatorPage.cs b/samples/TestWare.Samples.WinAppDriver/POM/Calculator/CalculatorPage.cs
index 8f597e1d..1b758ba6 100644
--- a/samples/TestWare.Samples.WinAppDriver/POM/Calculator/CalculatorPage.cs
+++ b/samples/TestWare.Samples.WinAppDriver/POM/Calculator/CalculatorPage.cs
@@ -1,6 +1,6 @@
using OpenQA.Selenium;
using OpenQA.Selenium.Appium;
-using TestWare.Engines.Appium.Extras;
+using TestWare.Engines.Common.Extras;
using TestWare.Engines.Appium.WinAppDriver.Factory;
using TestWare.Engines.Appium.WinAppDriver.Pages;
diff --git a/samples/TestWare.Samples.WinAppDriver/POM/Notepad/NotepadPage.cs b/samples/TestWare.Samples.WinAppDriver/POM/Notepad/NotepadPage.cs
index c33e6cee..c8e7c05a 100644
--- a/samples/TestWare.Samples.WinAppDriver/POM/Notepad/NotepadPage.cs
+++ b/samples/TestWare.Samples.WinAppDriver/POM/Notepad/NotepadPage.cs
@@ -1,5 +1,5 @@
using OpenQA.Selenium;
-using TestWare.Engines.Appium.Extras;
+using TestWare.Engines.Common.Extras;
using TestWare.Engines.Appium.WinAppDriver.Factory;
using TestWare.Engines.Appium.WinAppDriver.Pages;
diff --git a/samples/TestWare.Samples.WinAppDriver/POM/WindowsCalculator/WindowsCalculatorPage.cs b/samples/TestWare.Samples.WinAppDriver/POM/WindowsCalculator/WindowsCalculatorPage.cs
index f0c2e66e..91df494a 100644
--- a/samples/TestWare.Samples.WinAppDriver/POM/WindowsCalculator/WindowsCalculatorPage.cs
+++ b/samples/TestWare.Samples.WinAppDriver/POM/WindowsCalculator/WindowsCalculatorPage.cs
@@ -1,6 +1,6 @@
using OpenQA.Selenium.Appium;
using OpenQA.Selenium;
-using TestWare.Engines.Appium.Extras;
+using TestWare.Engines.Common.Extras;
using TestWare.Engines.Appium.WinAppDriver.Factory;
using TestWare.Engines.Appium.WinAppDriver.Pages;
using Humanizer;
diff --git a/samples/TestWare.Samples.WinAppDriver/TestWare.Samples.WinAppDriver.Desktop.csproj b/samples/TestWare.Samples.WinAppDriver/TestWare.Samples.WinAppDriver.Desktop.csproj
index 9e03f0a5..f678d77a 100644
--- a/samples/TestWare.Samples.WinAppDriver/TestWare.Samples.WinAppDriver.Desktop.csproj
+++ b/samples/TestWare.Samples.WinAppDriver/TestWare.Samples.WinAppDriver.Desktop.csproj
@@ -6,13 +6,13 @@
+
-
-
+
-
+
diff --git a/src/Engines/TestWare.Engines.Appium/AppiumManager.cs b/src/Engines/TestWare.Engines.Appium/AppiumManager.cs
index b044a99a..637b7b25 100644
--- a/src/Engines/TestWare.Engines.Appium/AppiumManager.cs
+++ b/src/Engines/TestWare.Engines.Appium/AppiumManager.cs
@@ -68,7 +68,7 @@ public string CollectEvidence(string destinationPath, string evidenceName)
}
var screenshot = ((ITakesScreenshot)appiumDriver).GetScreenshot();
- screenshot.SaveAsFile(Path.Combine(destinationPath, $"{evidenceName}.png"), ScreenshotImageFormat.Png);
+ screenshot.SaveAsFile(Path.Combine(destinationPath, $"{evidenceName}.png"));
}
catch
{
diff --git a/src/Engines/TestWare.Engines.Appium/Extras/ByFactory.cs b/src/Engines/TestWare.Engines.Appium/Extras/ByFactory.cs
deleted file mode 100644
index 10fc83ca..00000000
--- a/src/Engines/TestWare.Engines.Appium/Extras/ByFactory.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-#nullable enable
-using System.Globalization;
-using System.Reflection;
-using OpenQA.Selenium;
-using OpenQA.Selenium.Appium;
-
-namespace TestWare.Engines.Appium.Extras;
-
-///
-/// Provides instances of the object to the attributes.
-///
-internal static class ByFactory
-{
- ///
- /// Gets an instance of the class based on the specified attribute.
- ///
- /// The describing how to find the element.
- /// An instance of the class.
- public static By From(FindsByAttribute attribute)
- {
- var how = attribute.How;
- var usingValue = attribute.Using;
- switch (how)
- {
- case How.Id:
- return MobileBy.Id(usingValue);
- case How.Name:
- return MobileBy.Name(usingValue);
- case How.TagName:
- return MobileBy.TagName(usingValue);
- case How.ClassName:
- return MobileBy.ClassName(usingValue);
- case How.CssSelector:
- return By.CssSelector(usingValue);
- case How.LinkText:
- return By.LinkText(usingValue);
- case How.PartialLinkText:
- return By.PartialLinkText(usingValue);
- case How.XPath:
- return By.XPath(usingValue);
- case How.AccessibilityId:
- return MobileBy.AccessibilityId(usingValue);
- case How.Custom:
- if (attribute.CustomFinderType == null)
- {
- throw new ArgumentException("Cannot use How.Custom without supplying a custom finder type");
- }
-
- if (!attribute.CustomFinderType.IsSubclassOf(typeof(By)))
- {
- throw new ArgumentException("Custom finder type must be a descendent of the By class");
- }
-
- ConstructorInfo? ctor = attribute.CustomFinderType.GetConstructor(new Type[] { typeof(string) });
- if (ctor == null)
- {
- throw new ArgumentException("Custom finder type must expose a public constructor with a string argument");
- }
-
- By finder = (By)ctor.Invoke(new object?[] { usingValue });
-
- return finder;
- }
-
- throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Did not know how to construct How from how {0}, using {1}", how, usingValue));
- }
-}
diff --git a/src/Engines/TestWare.Engines.Appium/Extras/FindsByAttribute.cs b/src/Engines/TestWare.Engines.Appium/Extras/FindsByAttribute.cs
deleted file mode 100644
index f0a2bcd9..00000000
--- a/src/Engines/TestWare.Engines.Appium/Extras/FindsByAttribute.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using System.ComponentModel;
-using OpenQA.Selenium;
-
-namespace TestWare.Engines.Appium.Extras;
-
-public class FindsByAttribute : TestWare.Engines.Selenium.Extras.FindsByAttribute
-{
- [DefaultValue(How.Id)]
- new public How How { get; set; }
-
- public override By Finder
- {
- get
- {
- if (this.finder == null)
- {
- this.finder = ByFactory.From(this);
- }
-
- return this.finder;
- }
- }
-}
diff --git a/src/Engines/TestWare.Engines.Appium/Extras/PageFactory.cs b/src/Engines/TestWare.Engines.Appium/Extras/PageFactory.cs
deleted file mode 100644
index f4b74bae..00000000
--- a/src/Engines/TestWare.Engines.Appium/Extras/PageFactory.cs
+++ /dev/null
@@ -1,5 +0,0 @@
-namespace TestWare.Engines.Appium.Extras;
-
-public class PageFactory : Selenium.Extras.PageFactory
-{
-}
diff --git a/src/Engines/TestWare.Engines.Appium/Pages/MobilePage.cs b/src/Engines/TestWare.Engines.Appium/Pages/MobilePage.cs
index 59e89a33..b1a479a6 100644
--- a/src/Engines/TestWare.Engines.Appium/Pages/MobilePage.cs
+++ b/src/Engines/TestWare.Engines.Appium/Pages/MobilePage.cs
@@ -2,7 +2,7 @@
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.MultiTouch;
using System.Drawing;
-using TestWare.Engines.Appium.Extras;
+using TestWare.Engines.Common.Extras;
using TestWare.Engines.Appium.Factory;
using TestWare.Engines.Selenium.Pages;
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/AbstractFindsByAttribute.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/AbstractFindsByAttribute.cs
similarity index 99%
rename from src/Engines/TestWare.Engines.Selenium/Extras/AbstractFindsByAttribute.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/AbstractFindsByAttribute.cs
index 0f1f81da..828a5701 100644
--- a/src/Engines/TestWare.Engines.Selenium/Extras/AbstractFindsByAttribute.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/AbstractFindsByAttribute.cs
@@ -1,7 +1,7 @@
using System.ComponentModel;
using OpenQA.Selenium;
-namespace TestWare.Engines.Selenium.Extras;
+namespace TestWare.Engines.Common.Extras;
///
/// Base class for attributes to mark elements with methods by which to find a corresponding element on the page.
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/ByAll.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/ByAll.cs
similarity index 98%
rename from src/Engines/TestWare.Engines.Selenium/Extras/ByAll.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/ByAll.cs
index 7dda4a55..2790fa5c 100644
--- a/src/Engines/TestWare.Engines.Selenium/Extras/ByAll.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/ByAll.cs
@@ -5,7 +5,7 @@
using System.Text;
using OpenQA.Selenium;
-namespace TestWare.Engines.Selenium.Extras;
+namespace TestWare.Engines.Common.Extras;
///
/// Mechanism used to locate elements within a document using a series of lookups. This class will
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/ByChained.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/ByChained.cs
similarity index 98%
rename from src/Engines/TestWare.Engines.Selenium/Extras/ByChained.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/ByChained.cs
index d302c713..e3acc07e 100644
--- a/src/Engines/TestWare.Engines.Selenium/Extras/ByChained.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/ByChained.cs
@@ -5,7 +5,7 @@
using System.Text;
using OpenQA.Selenium;
-namespace TestWare.Engines.Selenium.Extras;
+namespace TestWare.Engines.Common.Extras;
///
/// Mechanism used to locate elements within a document using a series of other lookups. This class
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/ByFactory.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/ByFactory.cs
similarity index 93%
rename from src/Engines/TestWare.Engines.Selenium/Extras/ByFactory.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/ByFactory.cs
index 3cda7f11..cb5174f6 100644
--- a/src/Engines/TestWare.Engines.Selenium/Extras/ByFactory.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/ByFactory.cs
@@ -2,8 +2,9 @@
using System.Globalization;
using System.Reflection;
using OpenQA.Selenium;
+using OpenQA.Selenium.Appium;
-namespace TestWare.Engines.Selenium.Extras;
+namespace TestWare.Engines.Common.Extras;
///
/// Provides instances of the object to the attributes.
@@ -36,7 +37,9 @@ public static By From(FindsByAttribute attribute)
case How.PartialLinkText:
return By.PartialLinkText(usingValue);
case How.XPath:
- return By.XPath(usingValue);
+ return By.XPath(usingValue);
+ case How.AccessibilityId:
+ return MobileBy.AccessibilityId(usingValue);
case How.Custom:
if (attribute.CustomFinderType == null)
{
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/ByIdOrName.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/ByIdOrName.cs
similarity index 98%
rename from src/Engines/TestWare.Engines.Selenium/Extras/ByIdOrName.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/ByIdOrName.cs
index 36e875e1..9d2b2343 100644
--- a/src/Engines/TestWare.Engines.Selenium/Extras/ByIdOrName.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/ByIdOrName.cs
@@ -3,7 +3,7 @@
using System.Globalization;
using OpenQA.Selenium;
-namespace TestWare.Engines.Selenium.Extras;
+namespace TestWare.Engines.Common.Extras;
///
/// Finds element when the id or the name attribute has the specified value.
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/CacheLookupAttribute.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/CacheLookupAttribute.cs
similarity index 87%
rename from src/Engines/TestWare.Engines.Selenium/Extras/CacheLookupAttribute.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/CacheLookupAttribute.cs
index 95e1a73f..07c5edf0 100644
--- a/src/Engines/TestWare.Engines.Selenium/Extras/CacheLookupAttribute.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/CacheLookupAttribute.cs
@@ -1,5 +1,5 @@
-namespace TestWare.Engines.Selenium.Extras;
+namespace TestWare.Engines.Common.Extras;
///
/// Marks the element so that lookups to the browser page are cached. This class cannot be inherited.
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/DefaultElementLocator.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/DefaultElementLocator.cs
similarity index 98%
rename from src/Engines/TestWare.Engines.Selenium/Extras/DefaultElementLocator.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/DefaultElementLocator.cs
index cb9cd5fe..d422341d 100644
--- a/src/Engines/TestWare.Engines.Selenium/Extras/DefaultElementLocator.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/DefaultElementLocator.cs
@@ -3,7 +3,7 @@
using System.Collections.ObjectModel;
using OpenQA.Selenium;
-namespace TestWare.Engines.Selenium.Extras;
+namespace TestWare.Engines.Common.Extras;
///
/// A default locator for elements for use with the . This locator
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/DefaultPageObjectMemberDecorator.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/DefaultPageObjectMemberDecorator.cs
similarity index 99%
rename from src/Engines/TestWare.Engines.Selenium/Extras/DefaultPageObjectMemberDecorator.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/DefaultPageObjectMemberDecorator.cs
index 7fd57faf..4ab22a84 100644
--- a/src/Engines/TestWare.Engines.Selenium/Extras/DefaultPageObjectMemberDecorator.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/DefaultPageObjectMemberDecorator.cs
@@ -5,7 +5,7 @@
using OpenQA.Selenium;
using TestWare.Engines.Selenium.Extras.MemberBuilders;
-namespace TestWare.Engines.Selenium.Extras;
+namespace TestWare.Engines.Common.Extras;
///
/// Default decorator determining how members of a class which represent elements in a Page Object
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/ExpectedConditions.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/ExpectedConditions.cs
similarity index 99%
rename from src/Engines/TestWare.Engines.Selenium/Extras/ExpectedConditions.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/ExpectedConditions.cs
index 7a80173a..040bfa97 100644
--- a/src/Engines/TestWare.Engines.Selenium/Extras/ExpectedConditions.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/ExpectedConditions.cs
@@ -3,7 +3,7 @@
using System.Text.RegularExpressions;
using OpenQA.Selenium;
-namespace TestWare.Engines.Selenium.Extras;
+namespace TestWare.Engines.Common.Extras;
///
/// Supplies a set of common conditions that can be waited for using .
@@ -73,7 +73,7 @@ public static Func UrlMatches(string regex)
return (driver) =>
{
var currentUrl = driver.Url;
- var pattern = new Regex(regex, RegexOptions.IgnoreCase);
+ var pattern = new Regex(regex, RegexOptions.IgnoreCase, TimeSpan.FromSeconds(10));
var match = pattern.Match(currentUrl);
return match.Success;
};
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/FindsByAllAttribute.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/FindsByAllAttribute.cs
similarity index 95%
rename from src/Engines/TestWare.Engines.Selenium/Extras/FindsByAllAttribute.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/FindsByAllAttribute.cs
index 168bb0f2..bd88807c 100644
--- a/src/Engines/TestWare.Engines.Selenium/Extras/FindsByAllAttribute.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/FindsByAllAttribute.cs
@@ -1,5 +1,5 @@
-namespace TestWare.Engines.Selenium.Extras;
+namespace TestWare.Engines.Common.Extras;
///
/// Marks elements to indicate that found elements should match the criteria of
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/FindsByAttribute.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/FindsByAttribute.cs
similarity index 98%
rename from src/Engines/TestWare.Engines.Selenium/Extras/FindsByAttribute.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/FindsByAttribute.cs
index 8853dc6e..cb3467b8 100644
--- a/src/Engines/TestWare.Engines.Selenium/Extras/FindsByAttribute.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/FindsByAttribute.cs
@@ -3,7 +3,7 @@
using System.ComponentModel;
using OpenQA.Selenium;
-namespace TestWare.Engines.Selenium.Extras;
+namespace TestWare.Engines.Common.Extras;
///
/// Marks program elements with methods by which to find a corresponding element on the page. Used
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/FindsBySequenceAttribute.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/FindsBySequenceAttribute.cs
similarity index 96%
rename from src/Engines/TestWare.Engines.Selenium/Extras/FindsBySequenceAttribute.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/FindsBySequenceAttribute.cs
index 92831391..ed1b14c0 100644
--- a/src/Engines/TestWare.Engines.Selenium/Extras/FindsBySequenceAttribute.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/FindsBySequenceAttribute.cs
@@ -1,6 +1,6 @@
-namespace TestWare.Engines.Selenium.Extras;
+namespace TestWare.Engines.Common.Extras;
///
/// Marks elements to indicate that each on the field or
diff --git a/src/Engines/TestWare.Engines.Appium/Extras/How.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/How.cs
similarity index 96%
rename from src/Engines/TestWare.Engines.Appium/Extras/How.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/How.cs
index aa0424b2..a3d52fda 100644
--- a/src/Engines/TestWare.Engines.Appium/Extras/How.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/How.cs
@@ -1,4 +1,5 @@
-namespace TestWare.Engines.Appium.Extras;
+
+namespace TestWare.Engines.Common.Extras;
///
/// Provides the lookup methods for the FindsBy attribute (for using in PageObjects)
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/IElementLocator.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/IElementLocator.cs
similarity index 96%
rename from src/Engines/TestWare.Engines.Selenium/Extras/IElementLocator.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/IElementLocator.cs
index bbd210b5..8fe81455 100644
--- a/src/Engines/TestWare.Engines.Selenium/Extras/IElementLocator.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/IElementLocator.cs
@@ -2,7 +2,7 @@
using System.Collections.ObjectModel;
using OpenQA.Selenium;
-namespace TestWare.Engines.Selenium.Extras;
+namespace TestWare.Engines.Common.Extras;
///
/// Interface describing how elements are to be located by a .
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/IPageObjectMemberDecorator.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/IPageObjectMemberDecorator.cs
similarity index 94%
rename from src/Engines/TestWare.Engines.Selenium/Extras/IPageObjectMemberDecorator.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/IPageObjectMemberDecorator.cs
index 9c45442d..14e3246b 100644
--- a/src/Engines/TestWare.Engines.Selenium/Extras/IPageObjectMemberDecorator.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/IPageObjectMemberDecorator.cs
@@ -2,7 +2,7 @@
using System.Reflection;
-namespace TestWare.Engines.Selenium.Extras;
+namespace TestWare.Engines.Common.Extras;
///
/// Interface describing how members of a class which represent elements in a Page Object
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/MemberBuilders/IMemberBuilder.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/MemberBuilders/IMemberBuilder.cs
similarity index 97%
rename from src/Engines/TestWare.Engines.Selenium/Extras/MemberBuilders/IMemberBuilder.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/MemberBuilders/IMemberBuilder.cs
index 59ad7312..fd0678ea 100644
--- a/src/Engines/TestWare.Engines.Selenium/Extras/MemberBuilders/IMemberBuilder.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/MemberBuilders/IMemberBuilder.cs
@@ -18,6 +18,7 @@
using System.Diagnostics.CodeAnalysis;
using OpenQA.Selenium;
+using TestWare.Engines.Common.Extras;
namespace TestWare.Engines.Selenium.Extras.MemberBuilders;
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/MemberBuilders/WebElementBuilder.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/MemberBuilders/WebElementBuilder.cs
similarity index 97%
rename from src/Engines/TestWare.Engines.Selenium/Extras/MemberBuilders/WebElementBuilder.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/MemberBuilders/WebElementBuilder.cs
index 770b365c..e6e6d462 100644
--- a/src/Engines/TestWare.Engines.Selenium/Extras/MemberBuilders/WebElementBuilder.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/MemberBuilders/WebElementBuilder.cs
@@ -18,6 +18,7 @@
using System.Diagnostics.CodeAnalysis;
using OpenQA.Selenium;
+using TestWare.Engines.Common.Extras;
namespace TestWare.Engines.Selenium.Extras.MemberBuilders;
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/MemberBuilders/WebElementListBuilder.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/MemberBuilders/WebElementListBuilder.cs
similarity index 94%
rename from src/Engines/TestWare.Engines.Selenium/Extras/MemberBuilders/WebElementListBuilder.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/MemberBuilders/WebElementListBuilder.cs
index 7ac927e4..decff291 100644
--- a/src/Engines/TestWare.Engines.Selenium/Extras/MemberBuilders/WebElementListBuilder.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/MemberBuilders/WebElementListBuilder.cs
@@ -1,5 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using OpenQA.Selenium;
+using TestWare.Engines.Common.Extras;
namespace TestWare.Engines.Selenium.Extras.MemberBuilders;
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/MemberBuilders/WrappedElementBuilder.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/MemberBuilders/WrappedElementBuilder.cs
similarity index 94%
rename from src/Engines/TestWare.Engines.Selenium/Extras/MemberBuilders/WrappedElementBuilder.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/MemberBuilders/WrappedElementBuilder.cs
index 406245ea..750aa20e 100644
--- a/src/Engines/TestWare.Engines.Selenium/Extras/MemberBuilders/WrappedElementBuilder.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/MemberBuilders/WrappedElementBuilder.cs
@@ -1,5 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using OpenQA.Selenium;
+using TestWare.Engines.Common.Extras;
namespace TestWare.Engines.Selenium.Extras.MemberBuilders;
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/MemberBuilders/WrappedElementListBuilder.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/MemberBuilders/WrappedElementListBuilder.cs
similarity index 96%
rename from src/Engines/TestWare.Engines.Selenium/Extras/MemberBuilders/WrappedElementListBuilder.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/MemberBuilders/WrappedElementListBuilder.cs
index 8b9f088c..175bfa9a 100644
--- a/src/Engines/TestWare.Engines.Selenium/Extras/MemberBuilders/WrappedElementListBuilder.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/MemberBuilders/WrappedElementListBuilder.cs
@@ -1,5 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using OpenQA.Selenium;
+using TestWare.Engines.Common.Extras;
namespace TestWare.Engines.Selenium.Extras.MemberBuilders;
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/PageFactory.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/PageFactory.cs
similarity index 99%
rename from src/Engines/TestWare.Engines.Selenium/Extras/PageFactory.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/PageFactory.cs
index 391fda02..4fc46dfb 100644
--- a/src/Engines/TestWare.Engines.Selenium/Extras/PageFactory.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/PageFactory.cs
@@ -3,7 +3,7 @@
using System.Reflection;
using OpenQA.Selenium;
-namespace TestWare.Engines.Selenium.Extras;
+namespace TestWare.Engines.Common.Extras;
///
/// Provides the ability to produce Page Objects modeling a page. This class cannot be inherited.
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/RetryingElementLocator.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/RetryingElementLocator.cs
similarity index 99%
rename from src/Engines/TestWare.Engines.Selenium/Extras/RetryingElementLocator.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/RetryingElementLocator.cs
index 3acbf4a1..86859b52 100644
--- a/src/Engines/TestWare.Engines.Selenium/Extras/RetryingElementLocator.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/RetryingElementLocator.cs
@@ -3,7 +3,7 @@
using System.Collections.ObjectModel;
using OpenQA.Selenium;
-namespace TestWare.Engines.Selenium.Extras;
+namespace TestWare.Engines.Common.Extras;
///
/// A locator for elements for use with the that retries locating
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/WebDriverObjectProxy.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/WebDriverObjectProxy.cs
similarity index 96%
rename from src/Engines/TestWare.Engines.Selenium/Extras/WebDriverObjectProxy.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/WebDriverObjectProxy.cs
index 30885e29..28f46984 100644
--- a/src/Engines/TestWare.Engines.Selenium/Extras/WebDriverObjectProxy.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/WebDriverObjectProxy.cs
@@ -1,6 +1,6 @@
using OpenQA.Selenium;
-namespace TestWare.Engines.Selenium.Extras;
+namespace TestWare.Engines.Common.Extras;
///
/// Represents a base proxy class for objects used with the PageFactory.
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/WebElementEnumerable.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/WebElementEnumerable.cs
similarity index 96%
rename from src/Engines/TestWare.Engines.Selenium/Extras/WebElementEnumerable.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/WebElementEnumerable.cs
index 0e27ede9..2841bf49 100644
--- a/src/Engines/TestWare.Engines.Selenium/Extras/WebElementEnumerable.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/WebElementEnumerable.cs
@@ -1,6 +1,6 @@
using TestWare.Engines.Selenium.Extras;
-namespace TestWare.Engines.Selenium.Extras;
+namespace TestWare.Engines.Common.Extras;
///
/// Due to Linq optimized execution in dotnet core for IList, some methods lead to multiple elements retrieval.
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/WebElementListProxy.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/WebElementListProxy.cs
similarity index 97%
rename from src/Engines/TestWare.Engines.Selenium/Extras/WebElementListProxy.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/WebElementListProxy.cs
index 9d3376ba..92834ab6 100644
--- a/src/Engines/TestWare.Engines.Selenium/Extras/WebElementListProxy.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/WebElementListProxy.cs
@@ -3,7 +3,7 @@
using System.Collections;
using OpenQA.Selenium;
-namespace TestWare.Engines.Selenium.Extras;
+namespace TestWare.Engines.Common.Extras;
///
/// Represents a proxy class for a list of elements to be used with the PageFactory.
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/WebElementProxy.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/WebElementProxy.cs
similarity index 94%
rename from src/Engines/TestWare.Engines.Selenium/Extras/WebElementProxy.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/WebElementProxy.cs
index 3448a478..5c71fde4 100644
--- a/src/Engines/TestWare.Engines.Selenium/Extras/WebElementProxy.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/WebElementProxy.cs
@@ -5,7 +5,7 @@
using OpenQA.Selenium.Interactions.Internal;
using OpenQA.Selenium.Internal;
-namespace TestWare.Engines.Selenium.Extras;
+namespace TestWare.Engines.Common.Extras;
///
/// Intercepts the request to a single
@@ -63,9 +63,6 @@ public IWebElement WrappedElement
public string GetCssValue(string propertyName) => WrappedElement.GetCssValue(propertyName);
- [Obsolete ("Deprecated on IWebElement")]
- public string GetProperty(string propertyName) => WrappedElement.GetProperty(propertyName);
-
public void SendKeys(string text) => WrappedElement.SendKeys(text);
public void Submit() => WrappedElement.Submit();
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/WrapsElementFactory.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/WrapsElementFactory.cs
similarity index 96%
rename from src/Engines/TestWare.Engines.Selenium/Extras/WrapsElementFactory.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/WrapsElementFactory.cs
index 55906ade..5a663dbd 100644
--- a/src/Engines/TestWare.Engines.Selenium/Extras/WrapsElementFactory.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/WrapsElementFactory.cs
@@ -1,6 +1,6 @@
using OpenQA.Selenium;
-namespace TestWare.Engines.Selenium.Extras;
+namespace TestWare.Engines.Common.Extras;
internal static class WrapsElementFactory
{
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/WrapsElementListProxy.cs b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/WrapsElementListProxy.cs
similarity index 97%
rename from src/Engines/TestWare.Engines.Selenium/Extras/WrapsElementListProxy.cs
rename to src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/WrapsElementListProxy.cs
index 8e9cc2e3..fc9736d0 100644
--- a/src/Engines/TestWare.Engines.Selenium/Extras/WrapsElementListProxy.cs
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/Extras/WrapsElementListProxy.cs
@@ -4,7 +4,7 @@
using OpenQA.Selenium;
using TestWare.Engines.Selenium.Extras;
-namespace TestWare.Engines.Selenium.Extras;
+namespace TestWare.Engines.Common.Extras;
///
/// Represents a proxy class for a list of elements to be used with the PageFactory.
diff --git a/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/TestWare.Engines.Common.csproj b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/TestWare.Engines.Common.csproj
new file mode 100644
index 00000000..3797629f
--- /dev/null
+++ b/src/Engines/TestWare.Engines.Common/TestWare.Engines.Common/TestWare.Engines.Common.csproj
@@ -0,0 +1,15 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
diff --git a/src/Engines/TestWare.Engines.Selenium/Configuration/Capabilities.cs b/src/Engines/TestWare.Engines.Selenium/Configuration/Capabilities.cs
index 24f427a8..5c01917f 100644
--- a/src/Engines/TestWare.Engines.Selenium/Configuration/Capabilities.cs
+++ b/src/Engines/TestWare.Engines.Selenium/Configuration/Capabilities.cs
@@ -1,9 +1,9 @@
-using TestWare.Engines.Selenium.Factory;
-
-namespace TestWare.Engines.Selenium.Configuration;
+using TestWare.Engines.Selenium.Factory;
+
+namespace TestWare.Engines.Selenium.Configuration;
-internal class Capabilities
-{
+internal class Capabilities
+{
public string Name { get; set; }
public string Path { get; set; }
@@ -13,10 +13,11 @@ internal class Capabilities
public string BaseUrl { get; set; }
public int CommandTimeOutInMinutes { get; set; }
+
public IEnumerable Arguments { get; set; } = Enumerable.Empty();
-
- public SupportedBrowsers GetDriver()
- {
- return Enum.Parse(Driver, true);
+
+ public SupportedBrowsers GetDriver()
+ {
+ return Enum.Parse(Driver, true);
}
-}
+}
diff --git a/src/Engines/TestWare.Engines.Selenium/Extras/How.cs b/src/Engines/TestWare.Engines.Selenium/Extras/How.cs
deleted file mode 100644
index 4ff44fce..00000000
--- a/src/Engines/TestWare.Engines.Selenium/Extras/How.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-
-namespace TestWare.Engines.Selenium.Extras;
-
-///
-/// Provides the lookup methods for the FindsBy attribute (for using in PageObjects)
-///
-public enum How
-{
- ///
- /// Finds by
- ///
- Id,
-
- ///
- /// Finds by
- ///
- Name,
-
- ///
- /// Finds by
- ///
- TagName,
-
- ///
- /// Finds by
- ///
- ClassName,
-
- ///
- /// Finds by
- ///
- CssSelector,
-
- ///
- /// Finds by
- ///
- LinkText,
-
- ///
- /// Finds by
- ///
- PartialLinkText,
-
- ///
- /// Finds by
- ///
- XPath,
-
- ///
- /// Finds by a custom implementation.
- ///
- Custom
-}
diff --git a/src/Engines/TestWare.Engines.Selenium/Factory/ConfigurationTags.cs b/src/Engines/TestWare.Engines.Selenium/Factory/ConfigurationTags.cs
index 680cc5df..26a67ffa 100644
--- a/src/Engines/TestWare.Engines.Selenium/Factory/ConfigurationTags.cs
+++ b/src/Engines/TestWare.Engines.Selenium/Factory/ConfigurationTags.cs
@@ -1,10 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace TestWare.Engines.Selenium.Factory;
+namespace TestWare.Engines.Selenium.Factory;
public enum ConfigurationTags
{
diff --git a/src/Engines/TestWare.Engines.Selenium/Pages/PageBase.cs b/src/Engines/TestWare.Engines.Selenium/Pages/PageBase.cs
index d601ca2c..fd0eb089 100644
--- a/src/Engines/TestWare.Engines.Selenium/Pages/PageBase.cs
+++ b/src/Engines/TestWare.Engines.Selenium/Pages/PageBase.cs
@@ -2,7 +2,7 @@
using OpenQA.Selenium.Interactions;
using OpenQA.Selenium.Support.UI;
using TestWare.Core.Libraries;
-using TestWare.Engines.Selenium.Extras;
+using TestWare.Engines.Common.Extras;
namespace TestWare.Engines.Selenium.Pages;
diff --git a/src/Engines/TestWare.Engines.Selenium/Pages/WebPage.cs b/src/Engines/TestWare.Engines.Selenium/Pages/WebPage.cs
index 3a5d7f86..2ed6ad7f 100644
--- a/src/Engines/TestWare.Engines.Selenium/Pages/WebPage.cs
+++ b/src/Engines/TestWare.Engines.Selenium/Pages/WebPage.cs
@@ -1,5 +1,5 @@
using OpenQA.Selenium;
-using TestWare.Engines.Selenium.Extras;
+using TestWare.Engines.Common.Extras;
using TestWare.Engines.Selenium.Factory;
namespace TestWare.Engines.Selenium.Pages;
diff --git a/src/Engines/TestWare.Engines.Selenium/SeleniumManager.cs b/src/Engines/TestWare.Engines.Selenium/SeleniumManager.cs
index 082e6029..164bfbb1 100644
--- a/src/Engines/TestWare.Engines.Selenium/SeleniumManager.cs
+++ b/src/Engines/TestWare.Engines.Selenium/SeleniumManager.cs
@@ -94,7 +94,7 @@ public string CollectEvidence(string destinationPath, string evidenceName)
{
var instanceName = ContainerManager.GetNameFromInstance(webDriver);
var ss = ((ITakesScreenshot)webDriver).GetScreenshot();
- ss.SaveAsFile(Path.Combine(destinationPath, $"{evidenceName} - {instanceName}.png"), ScreenshotImageFormat.Png);
+ ss.SaveAsFile(Path.Combine(destinationPath, $"{evidenceName} - {instanceName}.png"));
}
catch (WebDriverException) { }
diff --git a/src/Engines/TestWare.Engines.Selenium/TestWare.Engines.Selenium.csproj b/src/Engines/TestWare.Engines.Selenium/TestWare.Engines.Selenium.csproj
index 36441f58..c0914bb9 100644
--- a/src/Engines/TestWare.Engines.Selenium/TestWare.Engines.Selenium.csproj
+++ b/src/Engines/TestWare.Engines.Selenium/TestWare.Engines.Selenium.csproj
@@ -7,11 +7,12 @@
-
+
+
diff --git a/src/Engines/TestWare.Engines.Selenoid/Configuration/Capabilities.cs b/src/Engines/TestWare.Engines.Selenoid/Configuration/Capabilities.cs
new file mode 100644
index 00000000..df136411
--- /dev/null
+++ b/src/Engines/TestWare.Engines.Selenoid/Configuration/Capabilities.cs
@@ -0,0 +1,34 @@
+using TestWare.Engines.Selenoid.Factory;
+
+namespace TestWare.Engines.Selenoid.Configuration;
+
+internal class Capabilities
+{
+ public string? Name { get; set; }
+
+ public string? Uri { get; set; }
+
+ public string? BrowserName { get; set; }
+
+ public string? BrowserVersion { get; set; }
+
+ public string? ScreenResolution { get; set; }
+
+ public int CommandTimeOutInMinutes { get; set; }
+
+ public bool EnableLog { get; set; }
+
+ public bool EnableVnc { get; set; }
+
+ public bool EnableVideo { get; set; }
+
+ public IEnumerable Arguments { get; set; } = Enumerable.Empty();
+
+ public SupportedBrowsers GetDriver()
+ {
+ if (BrowserName == null) {
+ throw new NullReferenceException("BrowserName capability was null.");
+ }
+ return Enum.Parse(BrowserName, true);
+ }
+}
\ No newline at end of file
diff --git a/src/Engines/TestWare.Engines.Selenoid/Factory/BrowserFactory.cs b/src/Engines/TestWare.Engines.Selenoid/Factory/BrowserFactory.cs
new file mode 100644
index 00000000..22e87359
--- /dev/null
+++ b/src/Engines/TestWare.Engines.Selenoid/Factory/BrowserFactory.cs
@@ -0,0 +1,77 @@
+using OpenQA.Selenium;
+using OpenQA.Selenium.Chrome;
+using OpenQA.Selenium.Edge;
+using OpenQA.Selenium.Firefox;
+using OpenQA.Selenium.Remote;
+using TestWare.Engines.Selenoid.Configuration;
+
+namespace TestWare.Engines.Selenoid.Factory;
+
+internal static class BrowserFactory
+{
+ private static string SELENOID_OPTIONS_KEY = "selenoid:options";
+
+ public static IWebDriver Create(Capabilities capabilities)
+ {
+ IWebDriver result = capabilities.GetDriver() switch
+ {
+ SupportedBrowsers.Chrome => CreateChromeDriver(capabilities),
+ SupportedBrowsers.Firefox => CreateFirefoxDriver(capabilities),
+ SupportedBrowsers.Edge => CreateEdgeDriver(capabilities),
+ SupportedBrowsers.Invalid => throw new NotImplementedException(),
+ _ => throw new NotSupportedException($"Browser type is invalid."),
+ };
+ return result;
+ }
+ private static IWebDriver CreateChromeDriver(Capabilities capabilities)
+ {
+ ChromeOptions options = new();
+ options.AddArguments(capabilities.Arguments);
+ options.AddAdditionalOption(SELENOID_OPTIONS_KEY, GenerateSelenoidCapabilities(capabilities));
+
+ if (capabilities.Uri == null) throw new ArgumentNullException(nameof(capabilities.Uri));
+ return new RemoteWebDriver(new Uri(capabilities.Uri), options.ToCapabilities());
+ }
+
+ private static IWebDriver CreateFirefoxDriver(Capabilities capabilities)
+ {
+ FirefoxOptions options = new();
+ options.AddArguments(capabilities.Arguments);
+ options.AddAdditionalOption(SELENOID_OPTIONS_KEY, GenerateSelenoidCapabilities(capabilities));
+
+ if (capabilities.Uri == null) throw new ArgumentNullException(nameof(capabilities.Uri));
+ return new RemoteWebDriver(new Uri(capabilities.Uri), options.ToCapabilities());
+ }
+
+ private static IWebDriver CreateEdgeDriver(Capabilities capabilities)
+ {
+ EdgeOptions options = new();
+ options.AddArguments(capabilities.Arguments);
+ options.AddAdditionalOption(SELENOID_OPTIONS_KEY, GenerateSelenoidCapabilities(capabilities));
+
+ if (capabilities.Uri == null) throw new ArgumentNullException(nameof(capabilities.Uri));
+ return new RemoteWebDriver(new Uri(capabilities.Uri), options.ToCapabilities());
+ }
+
+ private static Dictionary GenerateSelenoidCapabilities(Capabilities capabilities)
+ {
+ if (capabilities.BrowserName == null || capabilities.BrowserVersion == null || capabilities.ScreenResolution == null)
+ {
+ throw new ArgumentNullException(nameof(capabilities));
+ }
+ var browser = (SupportedBrowsers)Enum.Parse(typeof(SupportedBrowsers), capabilities.BrowserName);
+ var supportedBrowser = SupportedBrowsersHelper.GetBrowserName(browser) ?? throw new ArgumentNullException(nameof(browser));
+
+ return new Dictionary
+ {
+ ["browserName"] = supportedBrowser,
+ ["browserVersion"] = capabilities.BrowserVersion,
+ ["screenResolution"] = capabilities.ScreenResolution,
+ ["name"] = capabilities.BrowserName,
+ ["sessionTimeout"] = capabilities.CommandTimeOutInMinutes + "m",
+ ["enableLog"] = capabilities.EnableLog,
+ ["enableVnc"] = capabilities.EnableVnc,
+ ["enableVideo"] = capabilities.EnableVideo
+ };
+ }
+}
diff --git a/src/Engines/TestWare.Engines.Selenoid/Factory/BrowserNameAttribute.cs b/src/Engines/TestWare.Engines.Selenoid/Factory/BrowserNameAttribute.cs
new file mode 100644
index 00000000..9fb01c33
--- /dev/null
+++ b/src/Engines/TestWare.Engines.Selenoid/Factory/BrowserNameAttribute.cs
@@ -0,0 +1,23 @@
+namespace TestWare.Engines.Selenoid.Factory
+{
+ [AttributeUsage(AttributeTargets.Field)]
+ internal class BrowserNameAttribute : Attribute
+ {
+ private readonly string Name;
+
+ public BrowserNameAttribute(string name)
+ {
+ this.Name = name;
+ }
+
+ public static string GetPropertyName()
+ {
+ return "BrowserName";
+ }
+
+ public string GetValue()
+ {
+ return this.Name;
+ }
+ }
+}
diff --git a/src/Engines/TestWare.Engines.Selenoid/Factory/ConfigurationTags.cs b/src/Engines/TestWare.Engines.Selenoid/Factory/ConfigurationTags.cs
new file mode 100644
index 00000000..c0c30056
--- /dev/null
+++ b/src/Engines/TestWare.Engines.Selenoid/Factory/ConfigurationTags.cs
@@ -0,0 +1,8 @@
+namespace TestWare.Engines.Selenoid.Factory;
+
+public enum ConfigurationTags
+{
+ none = 0,
+ remotedriver = 1,
+ multiwebdriver = 2
+}
\ No newline at end of file
diff --git a/src/Engines/TestWare.Engines.Selenoid/Factory/SupportedBrowsers.cs b/src/Engines/TestWare.Engines.Selenoid/Factory/SupportedBrowsers.cs
new file mode 100644
index 00000000..e720ab90
--- /dev/null
+++ b/src/Engines/TestWare.Engines.Selenoid/Factory/SupportedBrowsers.cs
@@ -0,0 +1,27 @@
+using System.Reflection;
+
+namespace TestWare.Engines.Selenoid.Factory;
+
+public enum SupportedBrowsers
+{
+ Invalid = 0,
+ [BrowserName("chrome")]
+ Chrome = 1,
+ [BrowserName("firefox")]
+ Firefox = 2,
+ [BrowserName("MicrosoftEdge")]
+ Edge = 3
+}
+
+static class SupportedBrowsersHelper
+{
+ public static string? GetBrowserName(this SupportedBrowsers enumValue)
+ {
+ return enumValue
+ .GetType()
+ .GetMember(enumValue.ToString())
+ .First()?
+ .GetCustomAttribute()?
+ .GetValue();
+ }
+}
diff --git a/src/Engines/TestWare.Engines.Selenoid/Pages/PageBase.cs b/src/Engines/TestWare.Engines.Selenoid/Pages/PageBase.cs
new file mode 100644
index 00000000..56e21892
--- /dev/null
+++ b/src/Engines/TestWare.Engines.Selenoid/Pages/PageBase.cs
@@ -0,0 +1,129 @@
+using OpenQA.Selenium;
+using OpenQA.Selenium.Interactions;
+using OpenQA.Selenium.Support.UI;
+using TestWare.Core.Libraries;
+using TestWare.Engines.Common.Extras;
+
+namespace TestWare.Engines.Selenoid.Pages;
+
+public abstract class PageBase
+{
+ protected const int TimeToWait = 15;
+ protected const int NumberOfRetries = 5;
+
+ public IWebDriver? Driver { get; protected set; }
+
+ private readonly TimeSpan RetryAttemp = TimeSpan.FromMilliseconds(200);
+
+ protected void ClickElement(IWebElement element)
+ {
+ element = element ?? throw new ArgumentNullException(nameof(element), "Element to be clicked was null");
+
+ RetryPolicies.ExecuteActionWithRetries(
+ () =>
+ {
+ this.WaitUntilElementIsClickable(element);
+ element.Click();
+ },
+ numberOfRetries: NumberOfRetries,
+ retryAttemp: RetryAttemp);
+ }
+
+ protected void ClickInnerElement(IWebElement element)
+ {
+ element = element ?? throw new ArgumentNullException(nameof(element), "Element to be clicked was null");
+ if (Driver == null) throw new ArgumentNullException(nameof(Driver));
+
+ RetryPolicies.ExecuteActionWithRetries(
+ () =>
+ {
+ this.WaitUntilElementIsClickable(element);
+ var action = new Actions(Driver);
+ action.MoveToElement(element).Click().Perform();
+ },
+ numberOfRetries: NumberOfRetries,
+ retryAttemp: RetryAttemp);
+ }
+
+ protected void DoubleClickElement(IWebElement element)
+ {
+ element = element ?? throw new ArgumentNullException(nameof(element), "Element to be double clicked was null");
+
+ RetryPolicies.ExecuteActionWithRetries(
+ () =>
+ {
+ this.WaitUntilElementIsClickable(element);
+ new Actions(Driver).DoubleClick(element).Perform();
+ },
+ numberOfRetries: NumberOfRetries,
+ retryAttemp: RetryAttemp);
+ }
+
+ protected void SendKeysElement(IWebElement element, string text)
+ => this.SendKeysElement(element, text, TimeToWait);
+
+ protected void SendKeysElement(IWebElement element, string text, int timeToWait)
+ {
+ element = element ?? throw new ArgumentNullException(nameof(element), "Element to send keys was null");
+
+ RetryPolicies.ExecuteActionWithRetries(
+ () =>
+ {
+ this.WaitUntilElementIsClickable(element, timeToWait);
+ element.SendKeys(text);
+ },
+ numberOfRetries: NumberOfRetries,
+ retryAttemp: RetryAttemp);
+ }
+
+ protected void ClearElementText(IWebElement element)
+ => this.ClearElementText(element, TimeToWait);
+
+ protected void ClearElementText(IWebElement element, int timeToWait)
+ {
+ element = element ?? throw new ArgumentNullException(nameof(element), "Element to clear was null");
+
+ RetryPolicies.ExecuteActionWithRetries(
+ () =>
+ {
+ this.WaitUntilElementIsClickable(element, timeToWait);
+ element.Clear();
+ },
+ numberOfRetries: NumberOfRetries,
+ retryAttemp: RetryAttemp);
+ }
+
+ protected void WaitUntilElementIsClickable(IWebElement element)
+ => this.WaitUntilElementIsClickable(element, TimeToWait);
+
+ protected void WaitUntilElementIsClickable(IWebElement element, int timeToWait)
+ {
+ if (Driver == null) throw new ArgumentNullException(nameof(Driver));
+ var webDriverWait = new WebDriverWait(Driver, TimeSpan.FromSeconds(timeToWait));
+ webDriverWait.Until(ExpectedConditions.ElementToBeClickable(element));
+ }
+
+ protected void WaitUntilElementIsVisible(By locator)
+ => this.WaitUntilElementIsVisible(locator, TimeToWait);
+
+ protected void WaitUntilElementIsVisible(By locator, int timeToWait)
+ {
+ if (Driver == null) throw new ArgumentNullException(nameof(Driver));
+ var webDriverWait = new WebDriverWait(Driver, TimeSpan.FromSeconds(timeToWait));
+ webDriverWait.Until(ExpectedConditions.VisibilityOfAllElementsLocatedBy(locator));
+ }
+
+ protected void WaitUntilElementNotVisible(By locator, int secondsToWait)
+ {
+ if (Driver == null) throw new ArgumentNullException(nameof(Driver));
+ Thread.Sleep(1000);
+ var webDriverWait = new WebDriverWait(Driver, TimeSpan.FromSeconds(secondsToWait));
+ webDriverWait.Until(ExpectedConditions.InvisibilityOfElementLocated(locator));
+ }
+
+ protected static void ExecuteActionWithDelay(Action action, int secondsToDelayAction)
+ {
+ Thread.Sleep(secondsToDelayAction * 1000);
+ action.Invoke();
+ }
+}
diff --git a/src/Engines/TestWare.Engines.Selenoid/Pages/WebPage.cs b/src/Engines/TestWare.Engines.Selenoid/Pages/WebPage.cs
new file mode 100644
index 00000000..78a4fb9d
--- /dev/null
+++ b/src/Engines/TestWare.Engines.Selenoid/Pages/WebPage.cs
@@ -0,0 +1,33 @@
+using OpenQA.Selenium;
+using TestWare.Engines.Common.Extras;
+
+namespace TestWare.Engines.Selenoid.Pages;
+
+public abstract class WebPage : PageBase
+{
+ protected string? Url { get; set; }
+
+ protected WebPage(IWebDriver driver)
+ {
+ Driver = driver;
+ PageFactory.InitElements(Driver, this);
+ }
+
+ public void NavigateToUrl()
+ {
+ if (Url == null) throw new NullReferenceException("Url variable was null");
+ Driver?.Navigate().GoToUrl(new Uri(Url));
+ }
+
+ protected string AcceptDialog()
+ => this.AcceptDialog(TimeToWait);
+
+ protected string AcceptDialog(int timeToWait)
+ {
+ if (Driver == null) throw new NullReferenceException("Driver variable was null");
+ IAlert alert = ExpectedConditions.AlertIsPresent().Invoke(Driver);
+ var content = alert.Text;
+ alert.Accept();
+ return content;
+ }
+}
diff --git a/src/Engines/TestWare.Engines.Selenoid/SelenoidManager.cs b/src/Engines/TestWare.Engines.Selenoid/SelenoidManager.cs
new file mode 100644
index 00000000..43a9b5da
--- /dev/null
+++ b/src/Engines/TestWare.Engines.Selenoid/SelenoidManager.cs
@@ -0,0 +1,119 @@
+using Autofac;
+using Autofac.Core.Registration;
+using OpenQA.Selenium;
+using TestWare.Core;
+using TestWare.Core.Configuration;
+using TestWare.Core.Interfaces;
+using TestWare.Engines.Selenoid.Configuration;
+using TestWare.Engines.Selenoid.Factory;
+
+namespace TestWare.Engines.Selenoid
+{
+ public class SelenoidManager : EngineManagerBase, IEngineManager
+ {
+ private const string _name = "Selenoid";
+
+ private static void RegisterSingle(IEnumerable tags, TestConfiguration testConfiguration)
+ {
+ var configName = Enum.GetName(ConfigurationTags.remotedriver)?.ToUpperInvariant();
+ var capabilities = ConfigurationManager.GetCapabilities(testConfiguration, configName);
+ var singleCapability = capabilities.FirstOrDefault(x => tags.Contains(x?.Name?.ToUpperInvariant()));
+ if (singleCapability != null && !ContainerManager.ExistsType(singleCapability.GetType()))
+ {
+ var driver = BrowserFactory.Create(singleCapability);
+ ContainerManager.RegisterType(singleCapability.Name, driver);
+ }
+ else {
+ throw new NullReferenceException("No suitable capability was found.");
+ }
+ }
+
+ private static void RegisterMultiple(IEnumerable tags, TestConfiguration testConfiguration)
+ {
+ var configName = Enum.GetName(ConfigurationTags.multiwebdriver)?.ToUpperInvariant();
+ var capabilities = ConfigurationManager.GetCapabilities(testConfiguration, configName);
+ var multipleCapabilities = capabilities.Where(x => tags.Contains(x?.Name?.ToUpperInvariant()));
+
+ if (!multipleCapabilities.Any())
+ {
+ throw new NullReferenceException("No suitable capability was found.");
+ }
+
+ foreach (var capability in multipleCapabilities)
+ {
+ var driver = BrowserFactory.Create(capability);
+ ContainerManager.RegisterType(capability.Name, driver);
+ }
+ }
+
+ public string CollectEvidence(string destinationPath, string evidenceName)
+ {
+ var screenshotPath = string.Empty;
+
+ IEnumerable webDrivers;
+ using (var scope = ContainerManager.Container.BeginLifetimeScope())
+ {
+ webDrivers = scope.Resolve>();
+ }
+ foreach (var webDriver in webDrivers)
+ {
+ try
+ {
+ webDriver.SwitchTo().Alert();
+ // No screenshot because an Alert is present
+ }
+ catch (NoAlertPresentException)
+ {
+ var instanceName = ContainerManager.GetNameFromInstance(webDriver);
+ var ss = ((ITakesScreenshot)webDriver).GetScreenshot();
+ ss.SaveAsFile(Path.Combine(destinationPath, $"{evidenceName} - {instanceName}.png"));
+ }
+ catch (WebDriverException) { }
+
+ }
+
+ return screenshotPath;
+ }
+
+ public void Destroy()
+ {
+ try
+ {
+ IEnumerable webDrivers;
+ using (var scope = ContainerManager.Container.BeginLifetimeScope())
+ {
+ webDrivers = scope.Resolve>();
+ }
+
+ foreach (var webDriver in webDrivers)
+ {
+ webDriver.Close();
+ webDriver.Dispose();
+ }
+ }
+ catch (ComponentNotRegisteredException) { }
+ }
+
+ public string GetEngineName()
+ {
+ return _name;
+ }
+
+ public void Initialize(IEnumerable tags, TestConfiguration testConfiguration)
+ {
+ var normalizedTags = tags.Select(x => x.ToUpperInvariant()).ToArray();
+ var foundConfiguration = ConfigurationManager.GetValidConfiguration(tags);
+
+ switch (foundConfiguration)
+ {
+ case ConfigurationTags.remotedriver:
+ RegisterSingle(normalizedTags, testConfiguration);
+ break;
+
+ case ConfigurationTags.multiwebdriver:
+ RegisterMultiple(normalizedTags, testConfiguration);
+ break;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Engines/TestWare.Engines.Selenoid/TestWare.Engines.Selenoid.csproj b/src/Engines/TestWare.Engines.Selenoid/TestWare.Engines.Selenoid.csproj
new file mode 100644
index 00000000..1c51a306
--- /dev/null
+++ b/src/Engines/TestWare.Engines.Selenoid/TestWare.Engines.Selenoid.csproj
@@ -0,0 +1,18 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Engines/TestWare.Engines.WinAppDriver/Pages/WinAppDriverPage.cs b/src/Engines/TestWare.Engines.WinAppDriver/Pages/WinAppDriverPage.cs
index 9462ecac..a126d808 100644
--- a/src/Engines/TestWare.Engines.WinAppDriver/Pages/WinAppDriverPage.cs
+++ b/src/Engines/TestWare.Engines.WinAppDriver/Pages/WinAppDriverPage.cs
@@ -1,5 +1,5 @@
using TestWare.Engines.Selenium.Pages;
-using TestWare.Engines.Appium.Extras;
+using TestWare.Engines.Common.Extras;
using TestWare.Engines.Appium.WinAppDriver.Factory;
namespace TestWare.Engines.Appium.WinAppDriver.Pages;
@@ -10,6 +10,6 @@ public abstract class WinAppDriverPage : PageBase
protected WinAppDriverPage(IWindowsDriver driver)
{
Driver = driver;
- Selenium.Extras.PageFactory.InitElements(Driver, this);
+ PageFactory.InitElements(Driver, this);
}
}
diff --git a/src/Engines/TestWare.Engines.WinAppDriver/TestWare.Engines.Appium.WinAppDriver.csproj b/src/Engines/TestWare.Engines.WinAppDriver/TestWare.Engines.Appium.WinAppDriver.csproj
index 678a14c9..46b59d91 100644
--- a/src/Engines/TestWare.Engines.WinAppDriver/TestWare.Engines.Appium.WinAppDriver.csproj
+++ b/src/Engines/TestWare.Engines.WinAppDriver/TestWare.Engines.Appium.WinAppDriver.csproj
@@ -7,7 +7,7 @@
-
+