diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 000000000..0926a8ef8 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,10 @@ +{ + "permissions": { + "allow": [ + "Bash(dotnet build:*)", + "Bash(powershell -Command \"Get-ChildItem -Path . -Recurse -Include *.cs | ForEach-Object { (Get-Content $_.FullName) -replace ''Assert\\.AreEqual\\(true,\\s*'', ''Assert.IsTrue('' | Set-Content $_.FullName }\")", + "Bash(powershell:*)", + "Bash(dotnet clean:*)" + ] + } +} diff --git a/Bellatrix.LLM/Bellatrix.LLM.csproj b/Bellatrix.LLM/Bellatrix.LLM.csproj index ef6a46516..9a7171d19 100644 --- a/Bellatrix.LLM/Bellatrix.LLM.csproj +++ b/Bellatrix.LLM/Bellatrix.LLM.csproj @@ -1,23 +1,24 @@  - - net8.0 - enable - enable - + + net10.0 + enable + enable + - - - - - + + + + + - - - - - - - + + + + + + + + - + \ No newline at end of file diff --git a/Bellatrix.LLM/SemanticKernelService.cs b/Bellatrix.LLM/SemanticKernelService.cs index 5cd6e687b..6b420f1b3 100644 --- a/Bellatrix.LLM/SemanticKernelService.cs +++ b/Bellatrix.LLM/SemanticKernelService.cs @@ -54,7 +54,9 @@ private static void EnsureInitialized() return; var llmSettings = ConfigurationService.GetSection(); - + if (llmSettings == null) + return; + var genSettings = llmSettings.ModelSettings[0]; var embedSettings = llmSettings.ModelSettings[1]; diff --git a/Bellatrix.LLM/assertions/AiAssert.cs b/Bellatrix.LLM/assertions/AiAssert.cs index 377650fd3..ddee98de7 100644 --- a/Bellatrix.LLM/assertions/AiAssert.cs +++ b/Bellatrix.LLM/assertions/AiAssert.cs @@ -41,7 +41,7 @@ public static void AssertByPrompt(string assertInstruction) if (string.IsNullOrWhiteSpace(verdict) || !verdict.Contains("PASS", StringComparison.OrdinalIgnoreCase)) { - Assert.Fail($"AI Assert failed: {assertInstruction} - {verdict}"); + Assertions.Assert.Fail($"AI Assert failed: {assertInstruction} - {verdict}"); } Console.WriteLine("✅ AI Assert passed: " + assertInstruction); diff --git a/Bellatrix.LLM/plugins/SmartFailureAnalysisPlugin .cs b/Bellatrix.LLM/plugins/SmartFailureAnalysisPlugin .cs index 51343ca54..ffa4dcd7b 100644 --- a/Bellatrix.LLM/plugins/SmartFailureAnalysisPlugin .cs +++ b/Bellatrix.LLM/plugins/SmartFailureAnalysisPlugin .cs @@ -15,6 +15,7 @@ // The architecture and agent logic are original contributions by Anton Angelov, forming the foundation for a PhD dissertation. // Please cite or credit appropriately if reusing in academic or commercial work. +using Bellatrix.LLM.Settings; using Bellatrix.Plugins.Screenshots.Contracts; using Bellatrix.Plugins; using Bellatrix.Plugins.Screenshots.Plugins; @@ -26,12 +27,15 @@ public class SmartFailureAnalysisPlugin : Plugin, IScreenshotPlugin private readonly IScreenshotOutputProvider _screenshotOutputProvider; private readonly IViewSnapshotProvider _viewSnapshotProvider; private static ThreadLocal _screenshotPath = new ThreadLocal(); + private readonly bool _isEnabled; public SmartFailureAnalysisPlugin() { _screenshotOutputProvider = ServicesCollection.Current.Resolve(); _viewSnapshotProvider = ServicesCollection.Main.Resolve(); + var largeLanguageModelsSettings = ConfigurationService.GetSection(); + _isEnabled = largeLanguageModelsSettings?.EnableSmartFailureAnalysis ?? false; } public static void Add() @@ -60,6 +64,7 @@ public void ScreenshotGenerated(object sender, ScreenshotPluginEventArgs args) protected override void PreTestCleanup(object sender, PluginEventArgs e) { + if (!_isEnabled) return; if (e.TestOutcome == TestOutcome.Passed) { var log = Logger.GetLogs(); @@ -87,7 +92,7 @@ private void RunFailureAnalysisAsync(PluginEventArgs e) snapshot, _screenshotPath.Value ?? string.Empty); - + } catch (Exception ex) { @@ -112,4 +117,4 @@ private void RunFailureAnalysisAsync(PluginEventArgs e) //{extended} //"""); } -} +} \ No newline at end of file diff --git a/shared/SharedAssemblyInfo.targets b/shared/SharedAssemblyInfo.targets index e1aefd6d6..2fa77f9a4 100644 --- a/shared/SharedAssemblyInfo.targets +++ b/shared/SharedAssemblyInfo.targets @@ -1,34 +1,24 @@  - net8.0 - 11.0 + net10.0 + 14.0 DEBUG;STAGE;QA;LOCAL - 3.9.0.0 + 3.9.5.0 Automate The Planet Ltd. Automate The Planet Ltd. Bellatrix Test Framework - 3.9.0.0 - 3.9.0.0 + 3.9.5.0 + 3.9.5.0 en Automate The Planet Ltd. 2024 - - Added DevExtreme Components v1.2.0 - - Fixed parallel execution - - Added Excel Service - - Fixed formatting - - Added qTestId plugin - - Added Advanced CkEditor component - - Added DevExtreme Components v.1.0 - - .NET 8 Support - - Selenium Manager Support - - Upgrade All NuGet Packages - - Chrome Headless uses the new headless mode now - - Fixed grid execution driver additional options to Selenium 4 - - Added SetModelColumns method to grid extensions - - Upgraded Azure KeyVault Identity - - Upgraded WebDriver Manager Version + - added many new improvements to desktop module + - added support for .NET 10 + - added support to Appium 3.x + - improved test execution performance + - fix some LLM related issues - upgrade all 3rd-party NuGet packages - fix all known bugs @@ -45,7 +35,7 @@ true true - NU1701;NU1702;NU1705;NU1608; + NU1701;NU1702;NU1705;NU1608;NU1903;NU1902;NU1904;MSTEST0001 true @@ -55,6 +45,6 @@ false false true - NU1701;NU1702;NU1705;NU1608; + NU1701;NU1702;NU1705;NU1608;MSTEST0001 - + \ No newline at end of file diff --git a/src/Bellatrix.AWS/Bellatrix.AWS.csproj b/src/Bellatrix.AWS/Bellatrix.AWS.csproj index 123ec851e..1a06ae1c1 100644 --- a/src/Bellatrix.AWS/Bellatrix.AWS.csproj +++ b/src/Bellatrix.AWS/Bellatrix.AWS.csproj @@ -1,19 +1,19 @@  - - - - + + + + - + - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Bellatrix.Allure/Bellatrix.Results.Allure.csproj b/src/Bellatrix.Allure/Bellatrix.Results.Allure.csproj index 37cd49b63..93a0f7986 100644 --- a/src/Bellatrix.Allure/Bellatrix.Results.Allure.csproj +++ b/src/Bellatrix.Allure/Bellatrix.Results.Allure.csproj @@ -3,7 +3,7 @@ - + diff --git a/src/Bellatrix.Api/Bellatrix.API.csproj b/src/Bellatrix.Api/Bellatrix.API.csproj index 68cbcb806..dbf684743 100644 --- a/src/Bellatrix.Api/Bellatrix.API.csproj +++ b/src/Bellatrix.Api/Bellatrix.API.csproj @@ -1,20 +1,20 @@  - NU1701;NU1702;NU1705;NU1608;NU1902; + NU1701;NU1702;NU1705;NU1608;NU1902;MSTEST0001 - - - - - - - + + + + + + + diff --git a/src/Bellatrix.BugReporting/Bellatrix.BugReporting.csproj b/src/Bellatrix.BugReporting/Bellatrix.BugReporting.csproj index de2276813..23604a3f7 100644 --- a/src/Bellatrix.BugReporting/Bellatrix.BugReporting.csproj +++ b/src/Bellatrix.BugReporting/Bellatrix.BugReporting.csproj @@ -11,10 +11,10 @@ - - - - + + + + diff --git a/src/Bellatrix.CognitiveServices/Bellatrix.CognitiveServices.csproj b/src/Bellatrix.CognitiveServices/Bellatrix.CognitiveServices.csproj index d498f9ae6..72153d76a 100644 --- a/src/Bellatrix.CognitiveServices/Bellatrix.CognitiveServices.csproj +++ b/src/Bellatrix.CognitiveServices/Bellatrix.CognitiveServices.csproj @@ -3,7 +3,7 @@ - + diff --git a/src/Bellatrix.CognitiveServices/services/AssertedTableFormCell.cs b/src/Bellatrix.CognitiveServices/services/AssertedTableFormCell.cs index 0ea43de84..25fb5a442 100644 --- a/src/Bellatrix.CognitiveServices/services/AssertedTableFormCell.cs +++ b/src/Bellatrix.CognitiveServices/services/AssertedTableFormCell.cs @@ -1,4 +1,4 @@ -// +// // Copyright 2025 Automate The Planet Ltd. // Licensed under the Apache License, Version 2.0 (the "License"); // You may not use this file except in compliance with the License. diff --git a/src/Bellatrix.Core/Bellatrix.Core.csproj b/src/Bellatrix.Core/Bellatrix.Core.csproj index 2e453d156..5aa56203b 100644 --- a/src/Bellatrix.Core/Bellatrix.Core.csproj +++ b/src/Bellatrix.Core/Bellatrix.Core.csproj @@ -11,25 +11,25 @@ - + - + - - - - - - - + + + + + + + - - + + - - + + diff --git a/src/Bellatrix.Core/assertions/MSTestAssert.cs b/src/Bellatrix.Core/assertions/MSTestAssert.cs index b93b6269f..1ecfec026 100644 --- a/src/Bellatrix.Core/assertions/MSTestAssert.cs +++ b/src/Bellatrix.Core/assertions/MSTestAssert.cs @@ -71,7 +71,7 @@ public void AreDateTimesEqual(DateTime? expectedDate, DateTime? actualDate, int public void Fail(string message) => MU.Assert.Fail(message); - public void Fail(string message, params object[] parameters) => MU.Assert.Fail(message, parameters); + public void Fail(string message, params object[] parameters) => MU.Assert.Fail(string.Format(message, parameters)); public void IsFalse(bool condition) => MU.Assert.IsFalse(condition); @@ -93,7 +93,7 @@ public void AreDateTimesEqual(DateTime? expectedDate, DateTime? actualDate, int public void IsTrue(bool condition, string message) => MU.Assert.IsTrue(condition, message); - public void IsTrue(bool condition, string message, params object[] parameters) => MU.Assert.IsTrue(condition, message, parameters); + public void IsTrue(bool condition, string message, params object[] parameters) => MU.Assert.IsTrue(condition, string.Format(message, parameters)); public void Multiple(params Action[] assertions) => Assert.Multiple(assertions); } \ No newline at end of file diff --git a/src/Bellatrix.Core/utilities/WindowsProcessExtensions.cs b/src/Bellatrix.Core/utilities/WindowsProcessExtensions.cs index 530855b1f..4f6596364 100644 --- a/src/Bellatrix.Core/utilities/WindowsProcessExtensions.cs +++ b/src/Bellatrix.Core/utilities/WindowsProcessExtensions.cs @@ -32,7 +32,7 @@ public static IEnumerable GetChildProcesses(this Process process) return children; } - + public static Process GetParentProcess(this Process process) { int parentPid = 0; diff --git a/src/Bellatrix.Desktop/Bellatrix.Desktop.csproj b/src/Bellatrix.Desktop/Bellatrix.Desktop.csproj index e06f365f1..fc9cd07e3 100644 --- a/src/Bellatrix.Desktop/Bellatrix.Desktop.csproj +++ b/src/Bellatrix.Desktop/Bellatrix.Desktop.csproj @@ -2,20 +2,15 @@ - - - - - - - - - - - - + + + + + + + + - diff --git a/src/Bellatrix.Desktop/DesktopPluginsConfiguration.cs b/src/Bellatrix.Desktop/DesktopPluginsConfiguration.cs index 33e5ff03b..5800ed76b 100644 --- a/src/Bellatrix.Desktop/DesktopPluginsConfiguration.cs +++ b/src/Bellatrix.Desktop/DesktopPluginsConfiguration.cs @@ -150,7 +150,8 @@ public static void ConfigureLLM() { if (ConfigurationService.GetSection() == null) { - throw new ArgumentException("Could not load LargeLanguageModelsSettings section from testFrameworkSettings.json"); + Logger.LogError("Could not load LargeLanguageModelsSettings section from testFrameworkSettings.json"); + return; } try @@ -174,4 +175,4 @@ public static void ConfigureLLM() Logger.LogError(ex.ToString()); } } -} +} \ No newline at end of file diff --git a/src/Bellatrix.Desktop/components/Checkbox.cs b/src/Bellatrix.Desktop/components/CheckBox.cs similarity index 74% rename from src/Bellatrix.Desktop/components/Checkbox.cs rename to src/Bellatrix.Desktop/components/CheckBox.cs index 6b4eabd34..cfe3704be 100644 --- a/src/Bellatrix.Desktop/components/Checkbox.cs +++ b/src/Bellatrix.Desktop/components/CheckBox.cs @@ -31,7 +31,16 @@ public virtual void Check(bool isChecked = true) { if (isChecked && !WrappedElement.Selected || !isChecked && WrappedElement.Selected) { - Click(Checking, Checked); + Checking?.Invoke(this, new ComponentActionEventArgs(this)); + try + { + WrappedDriver.ExecuteScript("windows: toggle", WrappedElement); + } + catch + { + Click(null, null); + } + Checked?.Invoke(this, new ComponentActionEventArgs(this)); } } @@ -39,7 +48,16 @@ public virtual void Uncheck() { if (WrappedElement.Selected) { - Click(Unchecking, Unchecked); + Unchecking?.Invoke(this, new ComponentActionEventArgs(this)); + try + { + WrappedDriver.ExecuteScript("windows: toggle", WrappedElement); + } + catch + { + Click(null, null); + } + Unchecked?.Invoke(this, new ComponentActionEventArgs(this)); } } diff --git a/src/Bellatrix.Desktop/components/ComboBox.cs b/src/Bellatrix.Desktop/components/ComboBox.cs index dc47d359c..f28a6fca9 100644 --- a/src/Bellatrix.Desktop/components/ComboBox.cs +++ b/src/Bellatrix.Desktop/components/ComboBox.cs @@ -13,8 +13,11 @@ // https://bellatrix.solutions/ using System; using System.Diagnostics; +using System.Linq; using Bellatrix.Desktop.Contracts; using Bellatrix.Desktop.Events; +using Bellatrix.Desktop.Services; +using OpenQA.Selenium.Appium; namespace Bellatrix.Desktop; @@ -34,16 +37,65 @@ public virtual void SelectByText(string value) { Selecting?.Invoke(this, new ComponentActionEventArgs(this, value)); - if (WrappedElement.Text != value) + try { - WrappedElement.SendKeys(value); + var itemToSelect = this.CreateAllByTag("ListItem") + .FirstOrDefault(x => x.CreateByTag // Anton Angelov // https://bellatrix.solutions/ + using System; +using System.Collections.Generic; using Bellatrix.Desktop.Contracts; using Bellatrix.Desktop.Events; using Bellatrix.Layout; -using OpenQA.Selenium; -using OpenQA.Selenium.Remote; +using OpenQA.Selenium.Interactions; namespace Bellatrix.Desktop; @@ -25,8 +26,39 @@ public partial class Component : IComponentVisible, IComponent, ILayoutComponent internal virtual void Click(EventHandler clicking, EventHandler clicked) { clicking?.Invoke(this, new ComponentActionEventArgs(this)); + var clickSuccess = false; + + try + { + WrappedDriver.ExecuteScript("windows: invoke", WrappedElement); + clickSuccess = true; + } + catch + { + // ignore + } + + if (!clickSuccess) + { + try + { + this.ToBeVisible().WrappedElement.Click(); + clickSuccess = true; + } + catch + { + Logger.LogWarning($"Could not click component {ComponentName}." + + $"Component location: X={Location.X}, Y={Location.Y}" + + $"Component size: Width={Size.Width}, Height={Size.Height}"); + } + } - WrappedElement.Click(); + if (!clickSuccess) + { + new Actions(WrappedDriver, TimeSpan.Zero) + .MoveToElement(WrappedElement) + .Click().Perform(); + } clicked?.Invoke(this, new ComponentActionEventArgs(this)); } @@ -35,7 +67,19 @@ internal virtual void Hover(EventHandler hovering, Eve { hovering?.Invoke(this, new ComponentActionEventArgs(this)); - WrappedDriver.Mouse.MouseMove(WrappedElement.Coordinates); + try + { + WrappedDriver.ExecuteScript("windows: hover", new Dictionary + { + { "startElementId", WrappedElement.Id }, + { "endElementId", WrappedElement.Id }, + { "durationMs", 0 } + }); + } + catch + { + new Actions(WrappedDriver).MoveToElement(WrappedElement).Perform(); + } hovered?.Invoke(this, new ComponentActionEventArgs(this)); } @@ -53,8 +97,19 @@ internal virtual bool GetIsDisabled() internal virtual void SetText(EventHandler settingValue, EventHandler valueSet, string value) { settingValue?.Invoke(this, new ComponentActionEventArgs(this, value)); - WrappedElement.Clear(); - WrappedElement.SendKeys(value); + var element = WrappedElement; + + try + { + WrappedDriver.ExecuteScript("windows: setValue", element, value); + valueSet?.Invoke(this, new ComponentActionEventArgs(this, value)); + } + catch + { + WrappedElement.Clear(); + WrappedElement.SendKeys(value); + } + valueSet?.Invoke(this, new ComponentActionEventArgs(this, value)); } } \ No newline at end of file diff --git a/src/Bellatrix.Desktop/components/Core/Component.cs b/src/Bellatrix.Desktop/components/Core/Component.cs index 420d604e9..c29be5526 100644 --- a/src/Bellatrix.Desktop/components/Core/Component.cs +++ b/src/Bellatrix.Desktop/components/Core/Component.cs @@ -28,7 +28,9 @@ using Bellatrix.LLM; using Bellatrix.Plugins.Screenshots; using OpenQA.Selenium; +using OpenQA.Selenium.Appium; using OpenQA.Selenium.Appium.Windows; +using OpenQA.Selenium.Interactions; using OpenQA.Selenium.Remote; namespace Bellatrix.Desktop; @@ -38,14 +40,14 @@ public partial class Component { private readonly ComponentWaitService _elementWait; private readonly List _untils; - private WindowsElement _wrappedElement; + private AppiumElement _wrappedElement; private IViewSnapshotProvider _viewSnapshotProvider; private LargeLanguageModelsSettings _llmSettings; public Component() { _elementWait = new ComponentWaitService(); - WrappedDriver = ServicesCollection.Current.Resolve>(); + WrappedDriver = ServicesCollection.Current.Resolve(); _viewSnapshotProvider = ServicesCollection.Current.Resolve(); _llmSettings = ConfigurationService.GetSection(); _untils = new List(); @@ -59,22 +61,22 @@ public Component() public static event EventHandler CreatedComponents; public static event EventHandler ReturningWrappedElement; - public WindowsDriver WrappedDriver { get; } + public WindowsDriver WrappedDriver { get; } - public WindowsElement WrappedElement + public AppiumElement WrappedElement { get { - ReturningWrappedElement?.Invoke(this, new NativeElementActionEventArgs(GetAndWaitWebDriverElement())); - var element = GetWebDriverElement(); + var element = GetAndWaitWebDriverElement(); + ReturningWrappedElement?.Invoke(this, new NativeElementActionEventArgs(element)); return element; } internal set => _wrappedElement = value; } - public WindowsElement ParentWrappedElement { get; set; } + public AppiumElement ParentWrappedElement { get; set; } - public WindowsElement FoundWrappedElement { get; set; } + public AppiumElement FoundWrappedElement { get; set; } public int ElementIndex { get; set; } @@ -186,11 +188,14 @@ public virtual bool IsVisible public virtual void ScrollToVisible() { ScrollingToVisible?.Invoke(this, new ComponentActionEventArgs(this)); - - var touchActions = new RemoteTouchScreen(WrappedDriver); - System.Threading.Thread.Sleep(2000); - touchActions.Scroll(WrappedElement.Coordinates, 0, 0); - this.ToBeVisible().ToExists().WaitToBe(); + try + { + WrappedDriver.ExecuteScript("windows: scrollToVisible", WrappedElement); + } + catch + { + // ignore + } ScrolledToVisible?.Invoke(this, new ComponentActionEventArgs(this)); } @@ -218,7 +223,7 @@ public override string ToString() return sb.ToString(); } - protected WindowsElement GetAndWaitWebDriverElement() + protected AppiumElement GetAndWaitWebDriverElement() { if (_wrappedElement == null) { @@ -234,20 +239,21 @@ protected WindowsElement GetAndWaitWebDriverElement() if (until != null) { _elementWait.Wait(this, until); - if (until.GetType() == typeof(WaitNotExistStrategy)) - { - return _wrappedElement; - } + } + + if (until is WaitNotExistStrategy) + { + return _wrappedElement; } } _wrappedElement = GetWebDriverElement(); // ✅ Save if healing is enabled - if (_llmSettings.EnableSelfHealing) + if (_llmSettings != null && _llmSettings.EnableSelfHealing) { var snapshot = _viewSnapshotProvider.GetCurrentViewSnapshot(); - LocatorSelfHealingService.SaveWorkingLocator(By.ToString(), snapshot, WrappedDriver.Title); + LocatorSelfHealingService.SaveWorkingLocator(By.ToString(), snapshot, WrappedDriver.CurrentWindowHandle); } _untils.Clear(); @@ -255,7 +261,7 @@ protected WindowsElement GetAndWaitWebDriverElement() } catch (Exception ex) { - if (!_llmSettings.EnableSelfHealing) + if (_llmSettings == null || !_llmSettings.EnableSelfHealing) { throw new TimeoutException($"❌ Element not found: {By?.Value}", ex); } @@ -263,7 +269,7 @@ protected WindowsElement GetAndWaitWebDriverElement() Logger.LogWarning($"⚠️ Element not found with locator: {By}. Trying AI-based healing..."); var snapshot = _viewSnapshotProvider.GetCurrentViewSnapshot(); - var healedXpath = LocatorSelfHealingService.TryHeal(By.ToString(), snapshot, WrappedDriver.Title); + var healedXpath = LocatorSelfHealingService.TryHeal(By.ToString(), snapshot, WrappedDriver.CurrentWindowHandle); if (!string.IsNullOrEmpty(healedXpath)) { @@ -285,8 +291,9 @@ protected WindowsElement GetAndWaitWebDriverElement() return _wrappedElement; } - private WindowsElement GetWebDriverElement() + private AppiumElement GetWebDriverElement() { + var result = _wrappedElement; if (FoundWrappedElement != null) { return FoundWrappedElement; @@ -299,4 +306,4 @@ private WindowsElement GetWebDriverElement() return By.FindElement(WrappedDriver); } -} +} \ No newline at end of file diff --git a/src/Bellatrix.Desktop/components/Core/ComponentsList.cs b/src/Bellatrix.Desktop/components/Core/ComponentsList.cs index e659b9212..16938e89d 100644 --- a/src/Bellatrix.Desktop/components/Core/ComponentsList.cs +++ b/src/Bellatrix.Desktop/components/Core/ComponentsList.cs @@ -19,6 +19,7 @@ using Bellatrix.Desktop.Locators; using Bellatrix.Desktop.Services; using Bellatrix.Desktop.Untils; +using OpenQA.Selenium.Appium; using OpenQA.Selenium.Appium.Windows; namespace Bellatrix.Desktop.Controls.Core; @@ -27,14 +28,14 @@ public class ComponentsList : IEnumerable where TComponent : Component { private readonly FindStrategy _by; - private readonly WindowsElement _parenTComponent; + private readonly AppiumElement _parenTComponent; private readonly List _foundElements; private readonly bool _shouldCacheFoundElements; private List _cachedElements; public ComponentsList( FindStrategy by, - WindowsElement parenTComponent, + AppiumElement parenTComponent, bool shouldCacheFoundElements) : this(by, parenTComponent) { @@ -43,27 +44,27 @@ public ComponentsList( public ComponentsList( FindStrategy by, - WindowsElement parenTComponent) + AppiumElement parenTComponent) { _by = by; _parenTComponent = parenTComponent; _foundElements = new List(); - WrappedDriver = ServicesCollection.Current.Resolve>(); + WrappedDriver = ServicesCollection.Current.Resolve(); } public ComponentsList() { _foundElements = new List(); - WrappedDriver = ServicesCollection.Current.Resolve>(); + WrappedDriver = ServicesCollection.Current.Resolve(); } public ComponentsList(IEnumerable nativeElementList) { _foundElements = new List(nativeElementList); - WrappedDriver = ServicesCollection.Current.Resolve>(); + WrappedDriver = ServicesCollection.Current.Resolve(); } - public WindowsDriver WrappedDriver { get; } + public WindowsDriver WrappedDriver { get; } public TComponent this[int i] => GetAndWaitWebDriverElements().ElementAt(i); @@ -79,7 +80,7 @@ public int Count() } var nativeElements = WaitWebDriverElements(); - return nativeElements.Count(); + return nativeElements.Count; } public void ForEach(Action action) @@ -130,7 +131,7 @@ IEnumerable GetAndWaitNativeElements() foreach (var nativeElement in _by?.FindAllElements(_parenTComponent)) { var element = - elementRepository.CreateComponentThatIsFound(_by, (WindowsElement)nativeElement); + elementRepository.CreateComponentThatIsFound(_by, nativeElement); yield return element; } } diff --git a/src/Bellatrix.Desktop/components/EventHandlers/ListItemEventHandlers.cs b/src/Bellatrix.Desktop/components/EventHandlers/ListItemEventHandlers.cs new file mode 100644 index 000000000..a7cb1996b --- /dev/null +++ b/src/Bellatrix.Desktop/components/EventHandlers/ListItemEventHandlers.cs @@ -0,0 +1,33 @@ +// +// Copyright 2025 Automate The Planet Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); +// You may not use this file except in compliance with the License. +// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Anton Angelov +// https://bellatrix.solutions/ +using Bellatrix.Desktop.Events; + +namespace Bellatrix.Desktop.EventHandlers; + +public class ListItemEventHandlers : ComponentEventHandlers +{ + public override void SubscribeToAll() + { + base.SubscribeToAll(); + ListItem.Hovering += HoveringEventHandler; + ListItem.Hovered += HoveredEventHandler; + } + + public override void UnsubscribeToAll() + { + base.UnsubscribeToAll(); + ListItem.Hovering -= HoveringEventHandler; + ListItem.Hovered -= HoveredEventHandler; + } +} \ No newline at end of file diff --git a/src/Bellatrix.Desktop/components/ListItem.cs b/src/Bellatrix.Desktop/components/ListItem.cs new file mode 100644 index 000000000..75277e2f2 --- /dev/null +++ b/src/Bellatrix.Desktop/components/ListItem.cs @@ -0,0 +1,49 @@ +// +// Copyright 2025 Automate The Planet Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); +// You may not use this file except in compliance with the License. +// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Anton Angelov +// https://bellatrix.solutions/ +using System; +using System.Diagnostics; +using Bellatrix.Desktop.Events; + +namespace Bellatrix.Desktop; + +public class ListItem : Component +{ + public static event EventHandler Hovering; + public static event EventHandler Hovered; + + public virtual string InnerText => this.CreateByTag