Configuration: VS 2019 .Net 4.8 Unit Test solution/project using hybrid Selenium/UI Automation framework
Scenario: A script launches an IE 11 browser and navigates to an https website that authenticates access with a CAC/PIN.
Issue: The automation is successful in launching the browser, navigating to the URL, selecting the certificate from the Windows Security (Select a Certificate) dialog and correctly recognizes the 'ActiveClient Login' dialog and its PIN value field. HOWEVER, the UI Automation ValuePattern SetValue command sporadically sets the PIN value with something other than the supplied plain text PIN value! When it incorrectly sets the value, the process halts after the OK button is selected due to an invalid PIN entry attempt. Refer to code snippet at bottom for details.
What I've done to diagnose the issue so far without success:
- Placed Thread.Sleep commands between SetFocus command and SetValue command -AND- between SetValue and Invoke of OK button
- Adjusted length of Thread.Sleep in hopes to slow things down enough without throwing an exception for Alert dialog display
- Modeled process based on commands offered in following MS site: https://learn.microsoft.com/en-us/dotnet/framework/ui-automation/add-content-to-a-text-box-using-ui-automation
Background: Migrating CodedUI implementation to UI Automation since CodedUI is going away. The below CodedUI code snippet worked in VS 2015 .Net 4.7.1: Keyboard.SendKeys(plainTextPin, true);
==============
Code Snippet =================
AutomationElement dialog = FindActivClientPinDialog();
AutomationElement pinElement = null;
Wait.WaitForUiWithIntervalOverrides(() =>
{
pinElement = dialog.FindFirst(TreeScope.Descendants, new AndCondition(
new PropertyCondition(AutomationElement.NameProperty, PinName),
new PropertyCondition(AutomationElement.ClassNameProperty, PinEditClassName)));
return pinElement != null;
}, _waitForElementLocationGeneral);
pinElement.SetFocus();
Thread.Sleep(100);
Pattern.GetValuePattern(pinElement).SetValue(plainTextPin); **// THIS IS THE ISSUE**
Thread.Sleep(100);
AutomationElement buttonElement = selectionWindow.FindFirst(TreeScope.Children,
new AndCondition(new PropertyCondition(AutomationElement.ClassNameProperty, ButtonClassName),
new PropertyCondition(AutomationElement.NameProperty, OkayButtonName)));
if (!buttonElement.Current.IsEnabled)
{
throw new InvalidOperationException("The 'OK' button IS NOT ENABLED!");
}
Pattern.GetInvokePattern(buttonElement).Invoke();
=========
private static AutomationElement FindActivClientPinDialog()
{
AutomationElement acElement = null;
Wait.WaitForUiWithIntervalOverrides(() =>
{
acElement = AutomationElement.RootElement.FindFirst(TreeScope.Descendants,
new PropertyCondition(AutomationElement.ClassNameProperty, ActivClientClassNameProperty));
return acElement != null;
}, _waitForElementLocationGeneral);
Pattern.CheckResultAndThrow(acElement == null, "The ActivClient PIN selection dialog was NOT FOUND!");
return acElement;
}