Skip to content

Commit 6ec910d

Browse files
committed
Updated Desktop Components and Find Strategies
1 parent 71a1a84 commit 6ec910d

20 files changed

+240
-188
lines changed

src/Bellatrix.Desktop/components/CheckBox.cs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,33 @@ public virtual void Check(bool isChecked = true)
3131
{
3232
if (isChecked && !WrappedElement.Selected || !isChecked && WrappedElement.Selected)
3333
{
34-
Click(Checking, Checked);
34+
Checking?.Invoke(this, new ComponentActionEventArgs(this));
35+
try
36+
{
37+
WrappedDriver.ExecuteScript("windows: toggle", WrappedElement);
38+
}
39+
catch
40+
{
41+
Click(null, null);
42+
}
43+
Checked?.Invoke(this, new ComponentActionEventArgs(this));
3544
}
3645
}
3746

3847
public virtual void Uncheck()
3948
{
4049
if (WrappedElement.Selected)
4150
{
42-
Click(Unchecking, Unchecked);
51+
Unchecking?.Invoke(this, new ComponentActionEventArgs(this));
52+
try
53+
{
54+
WrappedDriver.ExecuteScript("windows: toggle", WrappedElement);
55+
}
56+
catch
57+
{
58+
Click(null, null);
59+
}
60+
Unchecked?.Invoke(this, new ComponentActionEventArgs(this));
4361
}
4462
}
4563

@@ -53,4 +71,4 @@ public virtual void Hover()
5371

5472
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
5573
public virtual bool IsChecked => WrappedElement.Selected;
56-
}
74+
}

src/Bellatrix.Desktop/components/ComboBox.cs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,25 @@ public virtual ListItem SelectedItem
5959
{
6060
get
6161
{
62-
return new ComponentsRepository().CreateComponentThatIsFound<ListItem>(null,
63-
(AppiumElement)WrappedDriver.ExecuteScript("windows: selectedItem", WrappedElement));
62+
var retryCount = 3;
63+
64+
while (retryCount-- > 0)
65+
{
66+
try
67+
{
68+
WrappedDriver.ExecuteScript("windows: expand", WrappedElement);
69+
var result = new ComponentsRepository().CreateComponentThatIsFound<ListItem>(null,
70+
(AppiumElement)WrappedDriver.ExecuteScript("windows: selectedItem", WrappedElement));
71+
WrappedDriver.ExecuteScript("windows: collapse", WrappedElement);
72+
return result;
73+
}
74+
catch
75+
{
76+
// ignore
77+
}
78+
}
79+
80+
return null;
6481
}
6582
}
6683

@@ -71,7 +88,7 @@ public virtual string InnerText
7188
{
7289
try
7390
{
74-
return SelectedItem.CreateByTag<Label>("Text").InnerText;
91+
return SelectedItem?.CreateByTag<Label>("Text").InnerText ?? string.Empty;
7592
}
7693
catch
7794
{

src/Bellatrix.Desktop/components/Core/Component.DefaultActions.cs

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,39 @@ public partial class Component : IComponentVisible, IComponent, ILayoutComponent
2626
internal virtual void Click(EventHandler<ComponentActionEventArgs> clicking, EventHandler<ComponentActionEventArgs> clicked)
2727
{
2828
clicking?.Invoke(this, new ComponentActionEventArgs(this));
29+
var clickSuccess = false;
2930

30-
////WrappedDriver.ExecuteScript("windows: click", new Dictionary<string, object>
31-
////{
32-
//// { "elementId", WrappedElement.Id },
33-
//// { "durationMs", 0 }
34-
////});
35-
WrappedElement.Click();
31+
try
32+
{
33+
WrappedDriver.ExecuteScript("windows: invoke", WrappedElement);
34+
clickSuccess = true;
35+
}
36+
catch
37+
{
38+
// ignore
39+
}
40+
41+
if (!clickSuccess)
42+
{
43+
try
44+
{
45+
this.ToBeVisible().WrappedElement.Click();
46+
clickSuccess = true;
47+
}
48+
catch
49+
{
50+
Logger.LogWarning($"Could not click component {ComponentName}." +
51+
$"Component location: X={Location.X}, Y={Location.Y}" +
52+
$"Component size: Width={Size.Width}, Height={Size.Height}");
53+
}
54+
}
55+
56+
if (!clickSuccess)
57+
{
58+
new Actions(WrappedDriver, TimeSpan.Zero)
59+
.MoveToElement(WrappedElement)
60+
.Click().Perform();
61+
}
3662

3763
clicked?.Invoke(this, new ComponentActionEventArgs(this));
3864
}
@@ -71,8 +97,19 @@ internal virtual bool GetIsDisabled()
7197
internal virtual void SetText(EventHandler<ComponentActionEventArgs> settingValue, EventHandler<ComponentActionEventArgs> valueSet, string value)
7298
{
7399
settingValue?.Invoke(this, new ComponentActionEventArgs(this, value));
74-
WrappedElement.Clear();
75-
WrappedElement.SendKeys(value);
100+
var element = WrappedElement;
101+
102+
try
103+
{
104+
WrappedDriver.ExecuteScript("windows: setValue", element, value);
105+
valueSet?.Invoke(this, new ComponentActionEventArgs(this, value));
106+
}
107+
catch
108+
{
109+
WrappedElement.Clear();
110+
WrappedElement.SendKeys(value);
111+
}
112+
76113
valueSet?.Invoke(this, new ComponentActionEventArgs(this, value));
77114
}
78115
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// <copyright file="ListBoxEventHandlers.cs" company="Automate The Planet Ltd.">
2+
// Copyright 2025 Automate The Planet Ltd.
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// You may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6+
// Unless required by applicable law or agreed to in writing, software
7+
// distributed under the License is distributed on an "AS IS" BASIS,
8+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9+
// See the License for the specific language governing permissions and
10+
// limitations under the License.
11+
// </copyright>
12+
// <author>Anton Angelov</author>
13+
// <site>https://bellatrix.solutions/</site>
14+
using Bellatrix.Desktop.Events;
15+
16+
namespace Bellatrix.Desktop.EventHandlers;
17+
18+
public class ListItemEventHandlers : ComponentEventHandlers
19+
{
20+
public override void SubscribeToAll()
21+
{
22+
base.SubscribeToAll();
23+
ListItem.Hovering += HoveringEventHandler;
24+
ListItem.Hovered += HoveredEventHandler;
25+
}
26+
27+
public override void UnsubscribeToAll()
28+
{
29+
base.UnsubscribeToAll();
30+
ListItem.Hovering -= HoveringEventHandler;
31+
ListItem.Hovered -= HoveredEventHandler;
32+
}
33+
}

src/Bellatrix.Desktop/components/ListItem.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// <copyright file="ListBox.cs" company="Automate The Planet Ltd.">
2-
// Copyright 2022 Automate The Planet Ltd.
2+
// Copyright 2025 Automate The Planet Ltd.
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// You may not use this file except in compliance with the License.
55
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
@@ -22,6 +22,8 @@ public class ListItem : Component
2222
public static event EventHandler<ComponentActionEventArgs> Hovering;
2323
public static event EventHandler<ComponentActionEventArgs> Hovered;
2424

25+
public virtual string InnerText => this.CreateByTag<Label>("Text").InnerText;
26+
2527
public virtual void Hover()
2628
{
2729
Hover(Hovering, Hovered);

src/Bellatrix.Desktop/components/Menu.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,14 @@ public void SelectOption(string option)
3131
{
3232
this.CreateAllByClass<Button>("MenuItem").First(x => x.GetAttribute("Name") == option).Click();
3333
}
34+
35+
public void SelectFirstOption()
36+
{
37+
this.CreateAllByClass<Button>("MenuItem").First().Click();
38+
}
39+
40+
public void SelectLastOption()
41+
{
42+
this.CreateAllByClass<Button>("MenuItem").Last().Click();
43+
}
3444
}
Lines changed: 49 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// <copyright file="Button.cs" company="Automate The Planet Ltd.">
2-
// Copyright 2022 Automate The Planet Ltd.
2+
// Copyright 2025 Automate The Planet Ltd.
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// You may not use this file except in compliance with the License.
55
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
@@ -12,10 +12,10 @@
1212
// <author>Anton Angelov</author>
1313
// <site>https://bellatrix.solutions/</site>
1414
using System;
15-
using Bellatrix.Desktop.Configuration;
1615
using Bellatrix.Desktop.Events;
17-
using Bellatrix.Desktop.Services;
18-
using OpenQA.Selenium.Appium.Windows;
16+
using Bellatrix.Desktop.Locators;
17+
using Bellatrix.Utilities;
18+
using OpenQA.Selenium;
1919

2020
namespace Bellatrix.Desktop;
2121

@@ -48,7 +48,6 @@ public virtual string WindowHandle
4848
return null;
4949
}
5050

51-
5251
return _windowHandle;
5352
}
5453
}
@@ -57,38 +56,54 @@ public virtual void Attach()
5756
{
5857
Attaching?.Invoke(this, new ComponentActionEventArgs(this));
5958

60-
this.ToExists().WaitToBe();
61-
62-
var currentAppConfiguration =
63-
ServicesCollection.Current.Resolve<AppInitializationInfo>("_currentAppConfiguration");
64-
currentAppConfiguration.WindowHandle = WindowHandle;
65-
var driver = WrappedWebDriverCreateService.Create(currentAppConfiguration, ServicesCollection.Current);
66-
67-
WrappedDriver.Quit();
68-
ServicesCollection.Current.UnregisterSingleInstance<WindowsDriver>();
69-
ServicesCollection.Current.RegisterInstance(driver);
70-
71-
Attached?.Invoke(this, new ComponentActionEventArgs(this));
72-
}
73-
74-
public virtual void Detach()
75-
{
76-
Attaching?.Invoke(this, new ComponentActionEventArgs(this));
77-
78-
var currentAppConfiguration = ServicesCollection.Current.Resolve<AppInitializationInfo>("_currentAppConfiguration");
79-
80-
if (currentAppConfiguration.WindowHandle != WindowHandle)
59+
if (By is FindNameStrategy byName)
8160
{
82-
throw new InvalidOperationException($"This window ({WindowHandle}) is not currently attached. Currently attached window: {currentAppConfiguration.WindowHandle}");
61+
try
62+
{
63+
Wait.Until(() =>
64+
{
65+
try
66+
{
67+
WrappedDriver.SwitchTo().Window(byName.Value);
68+
return true;
69+
}
70+
catch
71+
{
72+
return false;
73+
}
74+
}, 90);
75+
}
76+
catch (TimeoutException)
77+
{
78+
throw new NoSuchWindowException($"No window was found with name '{byName.Value}'");
79+
}
80+
}
81+
else
82+
{
83+
WrappedDriver.SwitchTo().Window(WindowHandle);
8384
}
84-
85-
currentAppConfiguration.WindowHandle = null;
86-
var driver = WrappedWebDriverCreateService.Create(currentAppConfiguration, ServicesCollection.Current);
87-
88-
WrappedDriver.Quit();
89-
ServicesCollection.Current.UnregisterSingleInstance<WindowsDriver>();
90-
ServicesCollection.Current.RegisterInstance(driver);
9185

9286
Attached?.Invoke(this, new ComponentActionEventArgs(this));
9387
}
88+
89+
// public virtual void Detach()
90+
// {
91+
// Attaching?.Invoke(this, new ComponentActionEventArgs(this));
92+
//
93+
// var currentAppConfiguration = ServicesCollection.Current.Resolve<AppInitializationInfo>("_currentAppConfiguration");
94+
//
95+
// if (currentAppConfiguration.WindowHandle != WindowHandle)
96+
// {
97+
// throw new InvalidOperationException($"This window ({WindowHandle}) is not currently attached. Currently attached window: {currentAppConfiguration.WindowHandle}");
98+
// }
99+
//
100+
// currentAppConfiguration.WindowHandle = null;
101+
// var driver = WrappedWebDriverCreateService.Create(currentAppConfiguration, ServicesCollection.Current);
102+
//
103+
// WrappedDriver.Quit();
104+
// ServicesCollection.Current.UnregisterSingleInstance<WindowsDriver>();
105+
// ServicesCollection.Current.RegisterInstance(driver);
106+
//
107+
// Attached?.Invoke(this, new ComponentActionEventArgs(this));
108+
// }
94109
}

src/Bellatrix.Desktop/findstrategies/ComponentRepositoryExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,4 @@ public static ComponentsList<TComponent> CreateAllByAutomationId<TComponent>(thi
6565

6666
public static ComponentsList<TComponent> CreateAllByXPath<TComponent>(this ComponentCreateService repo, string xpath)
6767
where TComponent : Component => new ComponentsList<TComponent>(new FindXPathStrategy(xpath), null);
68-
}
68+
}

src/Bellatrix.Desktop/findstrategies/Find.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ public sealed class Find
1818
static Find() => By = new FindStrategyFactory();
1919

2020
public static FindStrategyFactory By { get; }
21-
}
21+
}

src/Bellatrix.Desktop/findstrategies/FindAccessibilityIdStrategy.cs

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
// <author>Anton Angelov</author>
1313
// <site>https://bellatrix.solutions/</site>
1414
using System.Collections.Generic;
15+
using System.Linq;
16+
using OpenQA.Selenium;
1517
using OpenQA.Selenium.Appium;
16-
using OpenQA.Selenium.Appium.Windows;
1718

1819
namespace Bellatrix.Desktop.Locators;
1920

@@ -24,28 +25,18 @@ public FindAccessibilityIdStrategy(string name)
2425
{
2526
}
2627

27-
public override AppiumElement FindElement(WindowsDriver searchContext)
28+
public override AppiumElement FindElement(ISearchContext searchContext)
2829
{
29-
return searchContext.FindElement(MobileBy.AccessibilityId(Value));
30+
return searchContext.FindElement(MobileBy.AccessibilityId(Value)) as AppiumElement;
3031
}
3132

32-
public override IEnumerable<AppiumElement> FindAllElements(WindowsDriver searchContext)
33+
public override IEnumerable<AppiumElement> FindAllElements(ISearchContext searchContext)
3334
{
34-
return searchContext.FindElements(MobileBy.AccessibilityId(Value));
35-
}
36-
37-
public override AppiumElement FindElement(AppiumElement element)
38-
{
39-
return element.FindElement(MobileBy.AccessibilityId(Value));
40-
}
41-
42-
public override IEnumerable<AppiumElement> FindAllElements(AppiumElement element)
43-
{
44-
return element.FindElements(MobileBy.AccessibilityId(Value));
35+
return searchContext.FindElements(MobileBy.AccessibilityId(Value)).Select(el => el as AppiumElement);
4536
}
4637

4738
public override string ToString()
4839
{
4940
return $"AccessibilityId = {Value}";
5041
}
51-
}
42+
}

0 commit comments

Comments
 (0)