move attach to session.cs
Some checks are pending
Spell checking / Check Spelling (push) Waiting to run
Spell checking / Report (Push) (push) Blocked by required conditions
Spell checking / Report (PR) (push) Blocked by required conditions
Spell checking / Update PR (push) Waiting to run

This commit is contained in:
Zhaopeng Wang (from Dev Box) 2025-06-05 21:25:53 +08:00
parent 30e32a895a
commit c91ef00113
3 changed files with 102 additions and 119 deletions

View File

@ -11,7 +11,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.Windows;
using OpenQA.Selenium.Interactions;
using static Microsoft.ApplicationInsights.MetricDimensionNames.TelemetryContext;
using static Microsoft.PowerToys.UITest.WindowHelper;
namespace Microsoft.PowerToys.UITest
@ -23,17 +22,12 @@ namespace Microsoft.PowerToys.UITest
{
public WindowsDriver<WindowsElement> Root { get; set; }
private WindowsDriver<WindowsElement> WindowsDriver
{
get { return sessionHelper.GetDriver(); }
}
private WindowsDriver<WindowsElement> WindowsDriver { get; set; }
private List<IntPtr> windowHandlers = new List<IntPtr>();
private Window? MainWindow { get; set; }
private SessionHelper sessionHelper;
/// <summary>
/// Gets Main Window Handler
/// </summary>
@ -52,17 +46,17 @@ namespace Microsoft.PowerToys.UITest
/// </summary>
public bool? IsElevated { get; private set; }
public Session(SessionHelper pSessionHelper)
public Session(WindowsDriver<WindowsElement> pRoot, WindowsDriver<WindowsElement> pDriver, PowerToysModule scope, WindowSize size)
{
this.MainWindowHandler = IntPtr.Zero;
this.Root = pSessionHelper.GetRoot();
this.InitScope = pSessionHelper.Scope;
this.sessionHelper = pSessionHelper;
this.Root = pRoot;
this.WindowsDriver = pDriver;
this.InitScope = scope;
if (pSessionHelper.Size != WindowSize.UnSpecified)
if (size != WindowSize.UnSpecified)
{
// Attach to the scope & reset MainWindowHandler
this.Attach(pSessionHelper.Scope, pSessionHelper.Size);
this.Attach(scope, size);
}
}
@ -482,11 +476,63 @@ namespace Microsoft.PowerToys.UITest
{
this.IsElevated = null;
this.MainWindowHandler = IntPtr.Zero;
var windowHandleInfo = sessionHelper.Attach(windowName, size);
this.MainWindow = this.Find<Window>(windowHandleInfo.MainWindowTitle);
this.MainWindowHandler = windowHandleInfo.MainWindowHandler;
this.IsElevated = windowHandleInfo.IsElevated;
this.windowHandlers.Add(this.MainWindowHandler);
if (this.Root != null)
{
// search window handler by window title (admin and non-admin titles)
var timeout = TimeSpan.FromMinutes(2);
var retryInterval = TimeSpan.FromSeconds(5);
DateTime startTime = DateTime.Now;
List<(IntPtr HWnd, string Title)>? matchingWindows = null;
while (DateTime.Now - startTime < timeout)
{
matchingWindows = WindowHelper.ApiHelper.FindDesktopWindowHandler(
new[] { windowName, WindowHelper.AdministratorPrefix + windowName });
if (matchingWindows.Count > 0 && matchingWindows[0].HWnd != IntPtr.Zero)
{
break;
}
Task.Delay(retryInterval).Wait();
}
if (matchingWindows == null || matchingWindows.Count == 0 || matchingWindows[0].HWnd == IntPtr.Zero)
{
Assert.Fail($"Failed to attach. Window '{windowName}' not found after {timeout.TotalSeconds} seconds.");
}
// pick one from matching windows
this.MainWindowHandler = matchingWindows[0].HWnd;
this.IsElevated = matchingWindows[0].Title.StartsWith(WindowHelper.AdministratorPrefix);
ApiHelper.SetForegroundWindow(this.MainWindowHandler);
var hexWindowHandle = this.MainWindowHandler.ToInt64().ToString("x");
var appCapabilities = new AppiumOptions();
appCapabilities.AddAdditionalCapability("appTopLevelWindow", hexWindowHandle);
appCapabilities.AddAdditionalCapability("deviceName", "WindowsPC");
this.WindowsDriver = new WindowsDriver<WindowsElement>(new Uri(ModuleConfigData.Instance.GetWindowsApplicationDriverUrl()), appCapabilities);
this.windowHandlers.Add(this.MainWindowHandler);
if (size != WindowSize.UnSpecified)
{
WindowHelper.SetWindowSize(this.MainWindowHandler, size);
}
// Set MainWindow
MainWindow = Find<Window>(matchingWindows[0].Title);
}
else
{
Assert.IsNotNull(this.Root, $"Failed to attach to the window '{windowName}'. Root driver is null");
}
Task.Delay(3000).Wait();
return this;
}
@ -523,6 +569,35 @@ namespace Microsoft.PowerToys.UITest
return WindowHelper.GetWindowRect(this.MainWindowHandler);
}
/// <summary>
/// Launches the specified executable with optional arguments and simulates a delay before and after execution.
/// </summary>
/// <param name="executablePath">The full path to the executable to launch.</param>
/// <param name="arguments">Optional command-line arguments to pass to the executable.</param>
/// <param name="msPreAction">The number of milliseconds to wait before launching the executable. Default is 0 ms.</param>
/// <param name="msPostAction">The number of milliseconds to wait after launching the executable. Default is 2000 ms.</param>
public void StartExe(string executablePath, string arguments = "", int msPreAction = 0, int msPostAction = 2000)
{
PerformAction(
() =>
{
StartExeInternal(executablePath, arguments);
},
msPreAction,
msPostAction);
}
private void StartExeInternal(string executablePath, string arguments = "")
{
var processInfo = new ProcessStartInfo
{
FileName = executablePath,
Arguments = arguments,
UseShellExecute = true,
};
Process.Start(processInfo);
}
/// <summary>
/// Terminates all running processes that match the specified process name.
/// Waits for each process to exit after sending the kill signal.

View File

@ -32,15 +32,12 @@ namespace Microsoft.PowerToys.UITest
private Process? appDriver;
private Process? runner;
public PowerToysModule Scope { get; private set; }
public WindowSize Size { get; private set; }
private PowerToysModule scope;
[UnconditionalSuppressMessage("SingleFile", "IL3000:Avoid accessing Assembly file path when publishing as a single file", Justification = "<Pending>")]
public SessionHelper(PowerToysModule scope, WindowSize size)
public SessionHelper(PowerToysModule scope)
{
this.Scope = scope;
this.Size = size;
this.scope = scope;
this.sessionPath = ModuleConfigData.Instance.GetModulePath(scope);
this.locationPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
@ -88,7 +85,7 @@ namespace Microsoft.PowerToys.UITest
{
appDriver?.Kill();
appDriver?.WaitForExit(); // Optional: Wait for the process to exit
if (this.Scope == PowerToysModule.PowerToysSettings)
if (this.scope == PowerToysModule.PowerToysSettings)
{
runner?.Kill();
runner?.WaitForExit(); // Optional: Wait for the process to exit
@ -167,23 +164,7 @@ namespace Microsoft.PowerToys.UITest
}
/// <summary>
/// Start scope exe.
/// </summary>
public void StartScopeExe()
{
var processInfo = new ProcessStartInfo
{
FileName = this.locationPath + this.sessionPath,
Arguments = string.Empty,
UseShellExecute = true,
};
Process.Start(processInfo);
string windowName = ModuleConfigData.Instance.GetModuleWindowName(this.Scope);
var windowHandleInfo = this.Attach(windowName, this.Size);
}
/// <summary>
/// Exit scope exe.
/// Exit now exe.
/// </summary>
public void ExitScopeExe()
{
@ -201,7 +182,7 @@ namespace Microsoft.PowerToys.UITest
public void RestartScopeExe()
{
ExitScopeExe();
StartScopeExe();
StartExe(locationPath + sessionPath);
}
public WindowsDriver<WindowsElement> GetRoot() => this.Root;
@ -223,78 +204,5 @@ namespace Microsoft.PowerToys.UITest
this.ExitExe(winAppDriverProcessInfo.FileName);
this.appDriver = Process.Start(winAppDriverProcessInfo);
}
/// <summary>
/// Attaches to an existing exe by string window name.
/// The session should be attached when a new app is started.
/// </summary>
/// <param name="windowName">The window name to attach to.</param>
/// <param name="size">The window size to set. Default is no change to window size</param>
public WindowHandleInfo Attach(string windowName, WindowSize size = WindowSize.UnSpecified)
{
WindowHandleInfo res = new WindowHandleInfo { };
if (this.Root != null)
{
// search window handler by window title (admin and non-admin titles)
var timeout = TimeSpan.FromMinutes(2);
var retryInterval = TimeSpan.FromSeconds(5);
DateTime startTime = DateTime.Now;
List<(IntPtr HWnd, string Title)>? matchingWindows = null;
while (DateTime.Now - startTime < timeout)
{
matchingWindows = WindowHelper.ApiHelper.FindDesktopWindowHandler(
new[] { windowName, WindowHelper.AdministratorPrefix + windowName });
if (matchingWindows.Count > 0 && matchingWindows[0].HWnd != IntPtr.Zero)
{
break;
}
Task.Delay(retryInterval).Wait();
}
if (matchingWindows == null || matchingWindows.Count == 0 || matchingWindows[0].HWnd == IntPtr.Zero)
{
Assert.Fail($"Failed to attach. Window '{windowName}' not found after {timeout.TotalSeconds} seconds.");
}
// pick one from matching windows
res.MainWindowHandler = matchingWindows[0].HWnd;
res.MainWindowTitle = matchingWindows[0].Title;
res.IsElevated = matchingWindows[0].Title.StartsWith(WindowHelper.AdministratorPrefix);
ApiHelper.SetForegroundWindow(res.MainWindowHandler);
var hexWindowHandle = res.MainWindowHandler.ToInt64().ToString("x");
var appCapabilities = new AppiumOptions();
appCapabilities.AddAdditionalCapability("appTopLevelWindow", hexWindowHandle);
appCapabilities.AddAdditionalCapability("deviceName", "WindowsPC");
this.Driver = new WindowsDriver<WindowsElement>(new Uri(ModuleConfigData.Instance.GetWindowsApplicationDriverUrl()), appCapabilities);
if (size != WindowSize.UnSpecified)
{
WindowHelper.SetWindowSize(res.MainWindowHandler, size);
}
}
else
{
Assert.IsNotNull(this.Root, $"Failed to attach to the window '{windowName}'. Root driver is null");
}
Task.Delay(3000).Wait();
return res;
}
}
public struct WindowHandleInfo
{
public IntPtr MainWindowHandler { get; set; }
public string MainWindowTitle { get; set; }
public bool IsElevated { get; set; }
}
}

View File

@ -75,8 +75,8 @@ namespace Microsoft.PowerToys.UITest
System.Windows.Forms.SendKeys.SendWait("{ESC}");
}
this.sessionHelper = new SessionHelper(scope, size).Init();
this.Session = new Session(this.sessionHelper);
this.sessionHelper = new SessionHelper(scope).Init();
this.Session = new Session(this.sessionHelper.GetRoot(), this.sessionHelper.GetDriver(), scope, size);
if (this.scope == PowerToysModule.PowerToysSettings)
{
@ -447,7 +447,7 @@ namespace Microsoft.PowerToys.UITest
public void RestartScopeExe()
{
this.sessionHelper!.RestartScopeExe();
this.Session = new Session(sessionHelper);
this.Session = new Session(this.sessionHelper.GetRoot(), this.sessionHelper.GetDriver(), this.scope, this.size);
return;
}