Skip to content

Commit f27b1eb

Browse files
committed
Refactor UI automation and add new interfaces
Removed `PublicExtensions.cs` and added new interfaces `IUser32Driver` and `IUser32Element` for better UI automation using WebDriver. Updated `UiaDriver` to implement `IUser32Driver` and added `FindElement` and `FindElements` methods. Added `UiaElement` class to implement `IUser32Element` with methods for interacting with web elements. Introduced `LocalExtensions.cs` for JSON to dictionary conversion.
1 parent e3cd70a commit f27b1eb

File tree

5 files changed

+195
-92
lines changed

5 files changed

+195
-92
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System.Collections.Generic;
2+
using System.Text.Json;
3+
4+
namespace G4.WebDriver.Extensions
5+
{
6+
/// <summary>
7+
/// Provides extension methods for various utility operations used in the G4 WebDriver.
8+
/// </summary>
9+
internal static class LocalExtensions
10+
{
11+
/// <summary>
12+
/// Converts a JsonElement to a dictionary representation.
13+
/// </summary>
14+
/// <param name="element">The JsonElement to convert.</param>
15+
/// <returns>A dictionary representing the JsonElement.</returns>
16+
public static IDictionary<string, object> ConvertToDictionary(this JsonElement element)
17+
{
18+
// Get the raw JSON text
19+
var json = element.GetRawText();
20+
21+
// Deserialize the JSON into a dictionary
22+
return JsonSerializer.Deserialize<IDictionary<string, object>>(json);
23+
}
24+
}
25+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using System;
2+
3+
namespace G4.WebDriver.Remote.Uia
4+
{
5+
/// <summary>
6+
/// Represents a web driver that can interact with the user32.dll for native Windows UI automation.
7+
/// </summary>
8+
public interface IUser32Driver
9+
{
10+
/// <summary>
11+
/// Sends input scan codes to the WebDriver server.
12+
/// </summary>
13+
/// <param name="codes">The scan codes to send.</param>
14+
public void SendInputs(params string[] codes);
15+
16+
/// <summary>
17+
/// Sends input scan codes to the WebDriver server multiple times.
18+
/// </summary>
19+
/// <param name="repeat">The number of times to repeat the input.</param>
20+
/// <param name="codes">The scan codes to send.</param>
21+
public void SendInputs(int repeat, params string[] codes);
22+
23+
/// <summary>
24+
/// Sends text input to the WebDriver server.
25+
/// </summary>
26+
/// <param name="text">The text to send.</param>
27+
public void SendKeys(string text);
28+
29+
/// <summary>
30+
/// Sends each character of the specified text as a key input with a delay between each keystroke.
31+
/// </summary>
32+
/// <param name="text">The text to be sent as key inputs.</param>
33+
/// <param name="delay">The delay to wait between sending each key.</param>
34+
public void SendKeys(string text, TimeSpan delay);
35+
36+
/// <summary>
37+
/// Sends text input to the WebDriver server multiple times.
38+
/// </summary>
39+
/// <param name="repeat">The number of times to repeat the input.</param>
40+
/// <param name="text">The text to send.</param>
41+
public void SendKeys(int repeat, string text);
42+
}
43+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using G4.WebDriver.Models;
2+
3+
namespace G4.WebDriver.Remote.Uia
4+
{
5+
/// <summary>
6+
/// Represents a web element that can interact with the user32.dll for native Windows UI automation.
7+
/// </summary>
8+
public interface IUser32Element
9+
{
10+
/// <summary>
11+
/// Gets the UI Automation attribute value of a web element.
12+
/// </summary>
13+
/// <param name="name">The name of the attribute.</param>
14+
/// <returns>The attribute value as a string.</returns>
15+
string GetAttribute(string name);
16+
17+
/// <summary>
18+
/// Moves the mouse pointer over the specified web element using default mouse position data.
19+
/// </summary>
20+
/// <remarks>This method is designed for Windows environments only, utilizing the user32.dll for native mouse operations.</remarks>
21+
void MoveToElement();
22+
23+
/// <summary>
24+
/// Moves the mouse pointer over the specified web element using the provided mouse position data.
25+
/// </summary>
26+
/// <param name="positionData">The mouse position data to use when moving the mouse.</param>
27+
/// <remarks>This method is designed for Windows environments only, utilizing the user32.dll for native mouse operations.</remarks>
28+
void MoveToElement(MousePositionInputModel positionData);
29+
30+
/// <summary>
31+
/// Sends a native click command to a web element.
32+
/// </summary>
33+
void SendClick();
34+
35+
/// <summary>
36+
/// Sends a native double-click command to a web element.
37+
/// </summary>
38+
void SendDoubleClick();
39+
40+
/// <summary>
41+
/// Sets focus on a web element.
42+
/// </summary>
43+
void SetFocus();
44+
}
45+
}

src/G4.WebDriver.Remote.Uia/UiaDriver.cs

Lines changed: 55 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88
using System.Text.Json;
99
using System.Text;
1010
using System.Threading;
11+
using System.Collections.ObjectModel;
12+
using System.Linq;
1113

1214
namespace G4.WebDriver.Remote.Uia
1315
{
1416
/// <summary>
1517
/// Represents a WebDriver implementation for UI Automation (UIA), extending the <see cref="RemoteWebDriver"/>.
1618
/// </summary>
17-
public class UiaDriver : RemoteWebDriver
19+
public class UiaDriver : RemoteWebDriver, IUser32Driver
1820
{
1921
#region *** Constructors ***
2022
/// <summary>
@@ -187,20 +189,60 @@ public UiaDriver(IWebDriverCommandInvoker invoker, SessionModel session)
187189
PropertyNameCaseInsensitive = true
188190
};
189191

190-
/// <summary>
191-
/// Sends input scan codes to the WebDriver server.
192-
/// </summary>
193-
/// <param name="codes">The scan codes to send.</param>
192+
/// <inheritdoc />
193+
new public IWebElement FindElement(By by)
194+
{
195+
// Send a command to the WebDriver to find an element using the specified locator strategy and value.
196+
var response = Invoker.Invoke(nameof(WebDriverCommands.FindElement), new
197+
{
198+
by.Using, // The method used to locate the element (e.g., CSS selector, XPath).
199+
by.Value // The actual value of the locator (e.g., ".button-class", "//input[@id='submit']").
200+
});
201+
202+
// Extract the JSON response from the WebDriver command.
203+
var value = (JsonElement)response.Value;
204+
205+
// Convert the JSON response to a dictionary to access the element's details.
206+
var element = value.ConvertToDictionary();
207+
208+
// Get the element ID from the dictionary, which uniquely identifies the element within the current session.
209+
var id = element.First().Value.ToString();
210+
211+
// Return a new WebElement instance, initializing it with the WebDriver instance and the extracted element ID.
212+
return new UiaElement(driver: this, id);
213+
}
214+
215+
/// <inheritdoc />
216+
new public IEnumerable<IWebElement> FindElements(By by)
217+
{
218+
// Send a command to the WebDriver to find all elements that match the specified locator strategy and value.
219+
var response = Invoker.Invoke(nameof(WebDriverCommands.FindElements), new
220+
{
221+
by.Using, // The method used to locate the elements (e.g., CSS selector, XPath).
222+
by.Value // The actual value of the locator (e.g., ".button-class", "//input[@id='submit']").
223+
});
224+
225+
// Parse the JSON response to an array of elements.
226+
var value = ((JsonElement)response.Value).EnumerateArray().ToArray();
227+
228+
// Convert each element in the array to a dictionary to access its details,
229+
// and create a WebElement instance for each found element.
230+
var elements = value
231+
.Select(i => i.ConvertToDictionary())
232+
.Select(i => new UiaElement(driver: this, id: i.First().Value.ToString()) as IWebElement)
233+
.ToList();
234+
235+
// Return a read-only collection of the found WebElement instances.
236+
return new ReadOnlyCollection<IWebElement>(elements);
237+
}
238+
239+
/// <inheritdoc />
194240
public void SendInputs(params string[] codes)
195241
{
196242
SendInputs(1, codes);
197243
}
198244

199-
/// <summary>
200-
/// Sends input scan codes to the WebDriver server multiple times.
201-
/// </summary>
202-
/// <param name="repeat">The number of times to repeat the input.</param>
203-
/// <param name="codes">The scan codes to send.</param>
245+
/// <inheritdoc />
204246
public void SendInputs(int repeat, params string[] codes)
205247
{
206248
// Get the session ID from the WebDriver
@@ -244,20 +286,13 @@ public void SendInputs(int repeat, params string[] codes)
244286
}
245287
}
246288

247-
/// <summary>
248-
/// Sends text input to the WebDriver server.
249-
/// </summary>
250-
/// <param name="text">The text to send.</param>
289+
/// <inheritdoc />
251290
public void SendKeys(string text)
252291
{
253292
SendKeys(repeat: 1, text);
254293
}
255294

256-
/// <summary>
257-
/// Sends each character of the specified text as a key input with a delay between each keystroke.
258-
/// </summary>
259-
/// <param name="text">The text to be sent as key inputs.</param>
260-
/// <param name="delay">The delay to wait between sending each key.</param>
295+
/// <inheritdoc />
261296
public void SendKeys(string text, TimeSpan delay)
262297
{
263298
// Iterate through each character in the provided text.
@@ -272,11 +307,7 @@ public void SendKeys(string text, TimeSpan delay)
272307
}
273308
}
274309

275-
/// <summary>
276-
/// Sends text input to the WebDriver server multiple times.
277-
/// </summary>
278-
/// <param name="repeat">The number of times to repeat the input.</param>
279-
/// <param name="text">The text to send.</param>
310+
/// <inheritdoc />
280311
public void SendKeys(int repeat, string text)
281312
{
282313
// Get the session ID from the WebDriver

0 commit comments

Comments
 (0)