2025-02-28 03:08:08 -08:00
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
2025-03-14 17:04:23 +08:00
using System ;
2025-02-28 03:08:08 -08:00
using System.Diagnostics ;
using System.Diagnostics.CodeAnalysis ;
using System.Reflection ;
using Microsoft.VisualStudio.TestTools.UnitTesting ;
using OpenQA.Selenium.Appium ;
using OpenQA.Selenium.Appium.Windows ;
namespace Microsoft.PowerToys.UITest
{
/// <summary>
/// Nested class for test initialization.
/// </summary>
internal class SessionHelper
{
// Default session path is PowerToys settings dashboard
private readonly string sessionPath = ModuleConfigData . Instance . GetModulePath ( PowerToysModule . PowerToysSettings ) ;
2025-03-14 17:04:23 +08:00
private string? locationPath ;
2025-02-28 03:08:08 -08:00
private WindowsDriver < WindowsElement > Root { get ; set ; }
private WindowsDriver < WindowsElement > ? Driver { get ; set ; }
private Process ? appDriver ;
2025-03-14 17:04:23 +08:00
[UnconditionalSuppressMessage("SingleFile", "IL3000:Avoid accessing Assembly file path when publishing as a single file", Justification = "<Pending>")]
2025-02-28 03:08:08 -08:00
public SessionHelper ( PowerToysModule scope )
{
this . sessionPath = ModuleConfigData . Instance . GetModulePath ( scope ) ;
2025-03-14 17:04:23 +08:00
this . locationPath = Path . GetDirectoryName ( Assembly . GetExecutingAssembly ( ) . Location ) ;
2025-02-28 03:08:08 -08:00
var winAppDriverProcessInfo = new ProcessStartInfo
{
FileName = "C:\\Program Files (x86)\\Windows Application Driver\\WinAppDriver.exe" ,
Verb = "runas" ,
} ;
this . appDriver = Process . Start ( winAppDriverProcessInfo ) ;
var desktopCapabilities = new AppiumOptions ( ) ;
desktopCapabilities . AddAdditionalCapability ( "app" , "Root" ) ;
this . Root = new WindowsDriver < WindowsElement > ( new Uri ( ModuleConfigData . Instance . GetWindowsApplicationDriverUrl ( ) ) , desktopCapabilities ) ;
// Set default timeout to 5 seconds
this . Root . Manage ( ) . Timeouts ( ) . ImplicitWait = TimeSpan . FromSeconds ( 5 ) ;
}
/// <summary>
/// Initializes the test environment.
/// </summary>
/// <param name="scope">The PowerToys module to start.</param>
public SessionHelper Init ( )
{
2025-03-14 17:04:23 +08:00
this . StartExe ( locationPath + this . sessionPath ) ;
2025-02-28 03:08:08 -08:00
Assert . IsNotNull ( this . Driver , $"Failed to initialize the test environment. Driver is null." ) ;
return this ;
}
/// <summary>
/// Cleans up the test environment.
/// </summary>
public void Cleanup ( )
{
2025-03-14 17:04:23 +08:00
ExitScopeExe ( ) ;
2025-02-28 03:08:08 -08:00
try
{
appDriver ? . Kill ( ) ;
2025-03-14 17:04:23 +08:00
appDriver ? . WaitForExit ( ) ; // Optional: Wait for the process to exit
2025-02-28 03:08:08 -08:00
}
catch ( Exception ex )
{
// Handle exceptions if needed
Debug . WriteLine ( $"Exception during Cleanup: {ex.Message}" ) ;
}
}
/// <summary>
/// Starts a new exe and takes control of it.
/// </summary>
/// <param name="appPath">The path to the application executable.</param>
public void StartExe ( string appPath )
{
var opts = new AppiumOptions ( ) ;
opts . AddAdditionalCapability ( "app" , appPath ) ;
2025-03-14 17:04:23 +08:00
Console . WriteLine ( $"appPath: {appPath}" ) ;
2025-02-28 03:08:08 -08:00
this . Driver = new WindowsDriver < WindowsElement > ( new Uri ( ModuleConfigData . Instance . GetWindowsApplicationDriverUrl ( ) ) , opts ) ;
2025-03-14 17:04:23 +08:00
// Set default timeout to 5 seconds
this . Driver . Manage ( ) . Timeouts ( ) . ImplicitWait = TimeSpan . FromSeconds ( 5 ) ;
}
/// <summary>
/// Exit a exe.
/// </summary>
/// <param name="path">The path to the application executable.</param>
public void ExitExe ( string path )
{
// Exit Exe
string exeName = Path . GetFileNameWithoutExtension ( path ) ;
// PowerToys.FancyZonesEditor
Process [ ] processes = Process . GetProcessesByName ( exeName ) ;
foreach ( Process process in processes )
{
try
{
process . Kill ( ) ;
process . WaitForExit ( ) ; // Optional: Wait for the process to exit
}
catch ( Exception ex )
{
Assert . Fail ( $"Failed to terminate process {process.ProcessName} (ID: {process.Id}): {ex.Message}" ) ;
}
}
}
/// <summary>
/// Exit now exe.
/// </summary>
public void ExitScopeExe ( )
{
ExitExe ( sessionPath ) ;
}
/// <summary>
/// Restarts now exe and takes control of it.
/// </summary>
public void RestartScopeExe ( )
{
ExitExe ( sessionPath ) ;
StartExe ( locationPath + sessionPath ) ;
2025-02-28 03:08:08 -08:00
}
public WindowsDriver < WindowsElement > GetRoot ( ) = > this . Root ;
public WindowsDriver < WindowsElement > GetDriver ( )
{
Assert . IsNotNull ( this . Driver , $"Failed to get driver. Driver is null." ) ;
return this . Driver ;
}
}
}