diff --git a/Microsoft.Dynamics365.UIAutomation.Api.UCI/DTO/AppElementReference.cs b/Microsoft.Dynamics365.UIAutomation.Api.UCI/DTO/AppElementReference.cs
index 6626a0dd..1300ce64 100644
--- a/Microsoft.Dynamics365.UIAutomation.Api.UCI/DTO/AppElementReference.cs
+++ b/Microsoft.Dynamics365.UIAutomation.Api.UCI/DTO/AppElementReference.cs
@@ -299,8 +299,8 @@ public static class AppElements
{ "Nav_SitemapMenuItems", "//li[contains(@data-id,'sitemap-entity')]"},
{ "Nav_SitemapSwitcherButton", "//button[contains(@data-id,'sitemap-areaSwitcher-expand-btn')]"},
{ "Nav_SitemapSwitcherFlyout","//div[contains(@data-lp-id,'sitemap-area-switcher-flyout')]"},
- { "Nav_UCIAppContainer","//div[contains(@id,'AppLandingPageContentContainer')]"},
- { "Nav_UCIAppTile", ".//a[contains(@aria-label,'[NAME]')]"},
+ { "Nav_UCIAppContainer","//div[@id='AppLandingPageContentContainer']"},
+ { "Nav_UCIAppTile", "//div[@data-type='app-title' and @title='[NAME]']"},
//Grid
diff --git a/Microsoft.Dynamics365.UIAutomation.Api.UCI/Elements/Dialog.cs b/Microsoft.Dynamics365.UIAutomation.Api.UCI/Elements/Dialog.cs
index 4844d809..fe59c3fa 100644
--- a/Microsoft.Dynamics365.UIAutomation.Api.UCI/Elements/Dialog.cs
+++ b/Microsoft.Dynamics365.UIAutomation.Api.UCI/Elements/Dialog.cs
@@ -58,7 +58,7 @@ public void CloseOpportunity(double revenue, DateTime closeDate, string descript
///
/// Enum used to assign record to user or team
/// Name of the user or team to assign to
- public void Assign(Dialogs.AssignTo to, string userOrTeamName = "")
+ public void Assign(AssignTo to, string userOrTeamName = null)
{
_client.AssignDialog(to, userOrTeamName);
}
diff --git a/Microsoft.Dynamics365.UIAutomation.Api.UCI/WebClient.cs b/Microsoft.Dynamics365.UIAutomation.Api.UCI/WebClient.cs
index 2ef226b9..f4efd7be 100644
--- a/Microsoft.Dynamics365.UIAutomation.Api.UCI/WebClient.cs
+++ b/Microsoft.Dynamics365.UIAutomation.Api.UCI/WebClient.cs
@@ -12,6 +12,7 @@
using System.Security;
using System.Threading;
using System.Web;
+using OpenQA.Selenium.Interactions;
using OtpNet;
namespace Microsoft.Dynamics365.UIAutomation.Api.UCI
@@ -49,7 +50,7 @@ internal BrowserCommandResult InitializeModes()
if (Browser.Options.UCITestMode) queryParams += ",testmode=true";
if (Browser.Options.UCIPerformanceMode) queryParams += "&perf=true";
- if (!uri.Contains(queryParams) && !uri.Contains(System.Web.HttpUtility.UrlEncode(queryParams)))
+ if (!uri.Contains(queryParams) && !uri.Contains(HttpUtility.UrlEncode(queryParams)))
{
var testModeUri = uri + queryParams;
@@ -66,37 +67,23 @@ internal BrowserCommandResult InitializeModes()
public string[] OnlineDomains { get; set; }
#region PageWaits
-
- internal void WaitForLoginPage()
- {
- IWebDriver driver = this.Browser.Driver;
-
- driver.WaitUntilVisible(By.XPath(Elements.Xpath[Reference.Login.CrmMainPage])
- , TimeSpan.FromSeconds(60),
- e =>
- {
- //determine if we landed on the Unified Client Main page
- if (driver.HasElement(By.XPath(Elements.Xpath[Reference.Login.CrmUCIMainPage])))
- {
- driver.WaitForPageToLoad();
- driver.WaitForTransaction();
- }
- else //else we landed on the Web Client main page or app picker page
- SwitchToDefaultContent(driver);
- },
- "Login page failed."
- );
- }
-
- internal void WaitForMainPage()
- {
- IWebDriver driver = this.Browser.Driver;
- driver.WaitUntilVisible(By.XPath(Elements.Xpath[Reference.Login.CrmMainPage]));
- driver.WaitForPageToLoad();
- if (driver.HasElement(By.XPath(Elements.Xpath[Reference.Login.CrmUCIMainPage])))
- {
- driver.WaitForTransaction();
- }
+ internal bool WaitForMainPage(TimeSpan timeout, string errorMessage)
+ => WaitForMainPage(timeout, null, () => throw new InvalidOperationException(errorMessage));
+
+ internal bool WaitForMainPage(TimeSpan? timeout = null, Action successCallback = null, Action failureCallback = null)
+ {
+ IWebDriver driver = Browser.Driver;
+ timeout = timeout ?? Constants.DefaultTimeout;
+ successCallback = successCallback ?? (
+ _ => {
+ bool isUCI = driver.HasElement(By.XPath(Elements.Xpath[Reference.Login.CrmUCIMainPage]));
+ if (isUCI)
+ driver.WaitForTransaction();
+ });
+
+ var xpathToMainPage = By.XPath(Elements.Xpath[Reference.Login.CrmMainPage]);
+ var element = driver.WaitUntilVisible(xpathToMainPage, timeout, successCallback, failureCallback);
+ return element != null;
}
#endregion
@@ -132,7 +119,7 @@ private LoginResult Login(IWebDriver driver, Uri uri, SecureString username, Sec
bool success = EnterUserName(driver, username);
if (!success)
{
- var isUserAlreadyLogged = IsUserAlreadyLogged(driver);
+ var isUserAlreadyLogged = IsUserAlreadyLogged();
if (isUserAlreadyLogged)
{
SwitchToDefaultContent(driver);
@@ -165,21 +152,23 @@ private LoginResult Login(IWebDriver driver, Uri uri, SecureString username, Sec
ThinkTime(1000);
}
- EnterOneTimeCode(driver, mfaSecrectKey);
-
- ClickStaySignedIn(driver);
-
- ThinkTime(1000);
+ int attempts = 0;
+ bool entered;
+ do
+ {
+ entered = EnterOneTimeCode(driver, mfaSecrectKey);
+ success = ClickStaySignedIn(driver) || IsUserAlreadyLogged();
+ attempts++;
+ }
+ while (!success && attempts <= Constants.DefaultRetryAttempts); // retry to enter the otc-code, if its fail & it is requested again
+
+ if (entered && !success)
+ throw new InvalidOperationException("Somethig got wrong entering the OTC. Please check the MFA-SecrectKey in configuration.");
- return LoginResult.Success;
+ return success ? LoginResult.Success : LoginResult.Failure;
}
- private static bool IsUserAlreadyLogged(IWebDriver driver)
- {
- var xpathToMainPage = By.XPath(Elements.Xpath[Reference.Login.CrmMainPage]);
- bool result = driver.HasElement(xpathToMainPage);
- return result;
- }
+ private bool IsUserAlreadyLogged() => WaitForMainPage(2.Seconds());
private static string GenerateOneTimeCode(SecureString mfaSecrectKey)
{
@@ -213,41 +202,39 @@ private static void EnterPassword(IWebDriver driver, SecureString password)
input.Submit();
}
- private void EnterOneTimeCode(IWebDriver driver, SecureString mfaSecrectKey)
+ private bool EnterOneTimeCode(IWebDriver driver, SecureString mfaSecrectKey)
{
- int attempts = 0;
- while (true)
+ try
{
- try
- {
- IWebElement input = GetOtcInput(driver);
- if (input != null)
- {
- var oneTimeCode = GenerateOneTimeCode(mfaSecrectKey);
- input.SendKeys(oneTimeCode);
- input.Submit();
- return;
- }
- }
- catch (Exception e)
- {
- Trace.TraceInformation($"An Error ocur entering OTC. Attempt {attempts} of {Constants.DefaultRetryAttempts}. Exception: {e}");
- if (attempts >= Constants.DefaultRetryAttempts)
- throw;
- }
- attempts++;
- ThinkTime(Constants.DefaultRetryDelay);
+ IWebElement input = GetOtcInput(driver); // wait for the dialog, even if key is null, to print the right error
+ if (input == null)
+ return true;
+
+ if (mfaSecrectKey == null)
+ throw new InvalidOperationException("The application is wait for the OTC but your MFA-SecrectKey is not set. Please check your configuration.");
+
+ var oneTimeCode = GenerateOneTimeCode(mfaSecrectKey);
+ SetInputValue(driver, input, oneTimeCode, 1.Seconds());
+ input.Submit();
+ return true; // input found & code was entered
+ }
+ catch (Exception e)
+ {
+ var message = $"An Error occur entering OTC. Exception: {e.Message}";
+ Trace.TraceInformation(message);
+ throw new InvalidOperationException(message, e);
}
}
+
private static IWebElement GetOtcInput(IWebDriver driver)
=> driver.WaitUntilAvailable(By.XPath(Elements.Xpath[Reference.Login.OneTimeCode]), TimeSpan.FromSeconds(2));
- private static void ClickStaySignedIn(IWebDriver driver)
+ private static bool ClickStaySignedIn(IWebDriver driver)
{
var xpath = By.XPath(Elements.Xpath[Reference.Login.StaySignedIn]);
- driver.WaitUntilVisible(xpath, new TimeSpan(0, 0, 5),
- e => driver.ClickWhenAvailable(xpath));
+ var element = driver.ClickIfVisible(xpath, 5.Seconds());
+ return element != null;
}
private static void SwitchToDefaultContent(IWebDriver driver)
@@ -271,7 +258,22 @@ internal BrowserCommandResult PassThroughLogin(Uri uri)
{
driver.Navigate().GoToUrl(uri);
- WaitForLoginPage();
+ WaitForMainPage(60.Seconds(),
+ _ =>
+ {
+ //determine if we landed on the Unified Client Main page
+ var isUCI = driver.HasElement(By.XPath(Elements.Xpath[Reference.Login.CrmUCIMainPage]));
+ if (isUCI)
+ {
+ driver.WaitForPageToLoad();
+ driver.WaitForTransaction();
+ }
+ else
+ //else we landed on the Web Client main page or app picker page
+ SwitchToDefaultContent(driver);
+ },
+ () => new InvalidOperationException("Load Main Page Fail.")
+ );
return LoginResult.Success;
});
@@ -293,7 +295,7 @@ public void ADFSLoginAction(LoginRedirectEventArgs args)
//Insert any additional code as required for the SSO scenario
//Wait for CRM Page to load
- driver.WaitUntilVisible(By.XPath(Elements.Xpath[Reference.Login.CrmMainPage]), TimeSpan.FromSeconds(60), "Login page failed.");
+ WaitForMainPage(TimeSpan.FromSeconds(60), "Login page failed.");
SwitchToMainFrame(driver);
}
@@ -323,7 +325,7 @@ public void MSFTLoginAction(LoginRedirectEventArgs args)
//Insert any additional code as required for the SSO scenario
//Wait for CRM Page to load
- driver.WaitUntilVisible(By.XPath(Elements.Xpath[Reference.Login.CrmMainPage]), TimeSpan.FromSeconds(60), "Login page failed.");
+ WaitForMainPage(TimeSpan.FromSeconds(60), "Login page failed.");
SwitchToMainFrame(driver);
}
@@ -337,12 +339,14 @@ internal BrowserCommandResult OpenApp(string appName, int thinkTime = Cons
return Execute(GetOptions($"Open App {appName}"), driver =>
{
+ driver.WaitForPageToLoad();
driver.SwitchTo().DefaultContent();
//Handle left hand Nav in Web Client
- var success = TryOpenAppFromMenu(driver, appName, AppReference.Navigation.WebAppMenuButton) ||
- TryOpenAppFromMenu(driver, appName, AppReference.Navigation.UCIAppMenuButton) ||
- TryToClickInAppTile(appName, driver);
+ var success = TryToClickInAppTile(appName, driver) ||
+ TryOpenAppFromMenu(driver, appName, AppReference.Navigation.WebAppMenuButton) ||
+ TryOpenAppFromMenu(driver, appName, AppReference.Navigation.UCIAppMenuButton);
+
if (!success)
throw new InvalidOperationException($"App Name {appName} not found.");
@@ -355,36 +359,26 @@ internal BrowserCommandResult OpenApp(string appName, int thinkTime = Cons
private bool TryOpenAppFromMenu(IWebDriver driver, string appName, string appMenuButton)
{
- try
- {
- var xpathToAppMenu = By.XPath(AppElements.Xpath[appMenuButton]);
- bool found = driver.TryFindElement(xpathToAppMenu, out var appMenu);
- if (found)
- {
- appMenu.Click(true);
- OpenAppFromMenu(driver, appName);
- }
-
- return found;
- }
- catch (Exception e)
- {
- throw new InvalidOperationException($"App Button {appMenuButton} not found.", e);
- }
+ bool found = false;
+ var xpathToAppMenu = By.XPath(AppElements.Xpath[appMenuButton]);
+ driver.WaitUntilClickable(xpathToAppMenu, TimeSpan.FromSeconds(5),
+ appMenu =>
+ {
+ appMenu.Click(true);
+ OpenAppFromMenu(driver, appName);
+ found = true;
+ });
+ return found;
}
internal void OpenAppFromMenu(IWebDriver driver, string appName)
{
var container = driver.WaitUntilAvailable(By.XPath(AppElements.Xpath[AppReference.Navigation.AppMenuContainer]));
-
- var buttons = container.FindElements(By.TagName("button"));
-
- var button = buttons.FirstOrDefault(x => x.Text.Trim() == appName);
-
- if (button != null)
- button.Click(true);
- else
- throw new InvalidOperationException($"App Name {appName} not found.");
+ var xpathToButton = "//nav[@aria-hidden='false']//button//*[text()='[TEXT]']".Replace("[TEXT]", appName);
+ container.ClickWhenAvailable(By.XPath(xpathToButton),
+ TimeSpan.FromSeconds(1),
+ $"App Name {appName} not found."
+ );
driver.WaitUntilVisible(By.XPath(AppElements.Xpath[AppReference.Application.Shell]));
driver.WaitUntilVisible(By.XPath(AppElements.Xpath[AppReference.Navigation.SiteMapLauncherButton]));
@@ -392,15 +386,33 @@ internal void OpenAppFromMenu(IWebDriver driver, string appName)
private static bool TryToClickInAppTile(string appName, IWebDriver driver)
{
- //Switch to frame 0
- driver.SwitchTo().Frame(0);
- IWebElement tileContainer;
- bool success = driver.TryFindElement(By.XPath(AppElements.Xpath[AppReference.Navigation.UCIAppContainer]), out tileContainer);
- if (success)
- {
- var appTile = tileContainer.FindElement(By.XPath(AppElements.Xpath[AppReference.Navigation.UCIAppTile].Replace("[NAME]", appName)));
- appTile.Click(true);
- }
+ string message = null;
+ driver.WaitUntil(
+ d =>
+ {
+ try
+ {
+ driver.SwitchTo().Frame("AppLandingPage");
+ }
+ catch (NoSuchFrameException ex)
+ {
+ message = $"Frame AppLandingPage is not loaded. Exception: {ex.Message}";
+ Trace.TraceWarning(message);
+ return false;
+ }
+ return true;
+ },
+ TimeSpan.FromSeconds(30),
+ failureCallback: () => throw new InvalidOperationException(message)
+ );
+
+ var xpathToAppContainer = By.XPath(AppElements.Xpath[AppReference.Navigation.UCIAppContainer]);
+ var xpathToappTile = By.XPath(AppElements.Xpath[AppReference.Navigation.UCIAppTile].Replace("[NAME]", appName));
+
+ bool success = false;
+ driver.WaitUntilVisible(xpathToAppContainer, TimeSpan.FromSeconds(5),
+ appContainer => success = appContainer.ClickWhenAvailable(xpathToappTile, TimeSpan.FromSeconds(5)) != null
+ );
return success;
}
@@ -901,56 +913,47 @@ internal BrowserCommandResult ConfirmationDialog(bool ClickConfirmButton)
});
}
- internal BrowserCommandResult AssignDialog(Dialogs.AssignTo to, string userOrTeamName)
+ internal BrowserCommandResult AssignDialog(Dialogs.AssignTo to, string userOrTeamName = null)
{
+ userOrTeamName = userOrTeamName?.Trim() ?? string.Empty;
return this.Execute(GetOptions($"Assign to User or Team Dialog"), driver =>
{
var inlineDialog = this.SwitchToDialog();
- if (inlineDialog)
- {
- if (to != Dialogs.AssignTo.Me)
- {
- //Click the Option to Assign to User Or Team
- driver.WaitUntilClickable(By.XPath(AppElements.Xpath[AppReference.Dialogs.AssignDialogToggle]));
-
- var toggleButton = driver.WaitUntilAvailable(By.XPath(AppElements.Xpath[AppReference.Dialogs.AssignDialogToggle]), "Me/UserTeam toggle button unavailable");
- if (toggleButton.Text == "Me")
- toggleButton.Click();
-
- //Set the User Or Team
- var userOrTeamField = driver.WaitUntilAvailable(By.XPath(AppElements.Xpath[AppReference.Entity.TextFieldLookup]), "User field unavailable");
-
- if (userOrTeamField.FindElements(By.TagName("input")).Count > 0)
- {
- var input = userOrTeamField.FindElement(By.TagName("input"));
- if (input != null)
- {
- input.Click();
-
- driver.WaitForTransaction();
-
- input.SendKeys(userOrTeamName, true);
- }
- }
-
- //Pick the User from the list
- driver.WaitUntilVisible(By.XPath(AppElements.Xpath[AppReference.Dialogs.AssignDialogUserTeamLookupResults]));
-
- driver.WaitForTransaction();
+ if (!inlineDialog)
+ return false;
- var container = driver.FindElement(By.XPath(AppElements.Xpath[AppReference.Dialogs.AssignDialogUserTeamLookupResults]));
- var records = container.FindElements(By.TagName("li"));
- foreach (var record in records)
- {
- if (record.Text.StartsWith(userOrTeamName, StringComparison.OrdinalIgnoreCase))
- record.Click(true);
- }
- }
+ //Click the Option to Assign to User Or Team
+ var xpathToToggleButton = By.XPath(AppElements.Xpath[AppReference.Dialogs.AssignDialogToggle]);
+ var toggleButton = driver.WaitUntilClickable(xpathToToggleButton, "Me/UserTeam toggle button unavailable");
- //Click Assign
- var okButton = driver.FindElement(By.XPath(AppElements.Xpath[AppReference.Dialogs.AssignDialogOKButton]));
- okButton.Click(true);
+ if (to == Dialogs.AssignTo.Me)
+ {
+ if (toggleButton.Text != "Me")
+ toggleButton.Click();
}
+ else
+ {
+ if (toggleButton.Text == "Me")
+ toggleButton.Click();
+
+ //Set the User Or Team
+ var userOrTeamField = driver.WaitUntilAvailable(By.XPath(AppElements.Xpath[AppReference.Entity.TextFieldLookup]), "User field unavailable");
+ var input = userOrTeamField.ClickWhenAvailable(By.TagName("input"), "User field unavailable");
+ input.SendKeys(userOrTeamName, true);
+
+ ThinkTime(2000);
+
+ //Pick the User from the list
+ var container = driver.WaitUntilVisible(By.XPath(AppElements.Xpath[AppReference.Dialogs.AssignDialogUserTeamLookupResults]));
+ container.WaitUntil(
+ c => c.FindElements(By.TagName("li")).FirstOrDefault(r => r.Text.StartsWith(userOrTeamName, StringComparison.OrdinalIgnoreCase)),
+ successCallback: e => e.Click(true),
+ failureCallback: () => throw new InvalidOperationException($"None {to} found which match with '{userOrTeamName}'"));
+ }
+
+ //Click Assign
+ driver.ClickWhenAvailable(By.XPath(AppElements.Xpath[AppReference.Dialogs.AssignDialogOKButton]), TimeSpan.FromSeconds(5),
+ "Unable to click the OK button in the assign dialog");
return true;
});
@@ -1903,6 +1906,19 @@ internal BrowserCommandResult SetValue(string field, string value)
});
}
+ private void SetInputValue(IWebDriver driver, IWebElement input, string value, TimeSpan? thinktime = null)
+ {
+ input.SendKeys(Keys.Control + "a");
+ input.SendKeys(Keys.Backspace);
+ driver.WaitForTransaction();
+
+ if (string.IsNullOrWhiteSpace(value))
+ return;
+
+ input.SendKeys(value, true);
+ driver.WaitForTransaction();
+ ThinkTime(thinktime ?? 3.Seconds());
+ }
///
/// Sets the value of a Lookup, Customer, Owner or ActivityParty Lookup which accepts only a single value.
///
@@ -2223,6 +2239,7 @@ private void TrySetDateValue(IWebDriver driver, IWebElement dateField, string da
failureCallback: () => throw new InvalidOperationException($"Timeout after 10 seconds. Expected: {date}. Actual: {dateField.GetAttribute("value")}")
);
}
+
private void ClearFieldValue(IWebElement field)
{
if (field.GetAttribute("value").Length > 0)
@@ -2230,6 +2247,7 @@ private void ClearFieldValue(IWebElement field)
field.SendKeys(Keys.Control + "a");
field.SendKeys(Keys.Backspace);
}
+
ThinkTime(500);
}
@@ -2637,7 +2655,7 @@ internal BrowserCommandResult GetValue(MultiValueOptionSet
expandCollapseButtons.First().Click(true);
}
- var returnValue = new MultiValueOptionSet { Name = option.Name };
+ var returnValue = new MultiValueOptionSet {Name = option.Name};
xpath = AppElements.Xpath[AppReference.MultiSelect.SelectedRecordLabel].Replace("[NAME]", Elements.ElementId[option.Name]);
var labelItems = driver.FindElements(By.XPath(xpath));
@@ -2909,7 +2927,7 @@ internal BrowserCommandResult GetHeaderValue(BooleanItem control)
{
var xpathToContainer = AppElements.Xpath[AppReference.Entity.Header.DateTimeFieldContainer].Replace("[NAME]", control.Name);
return Execute(GetOptions($"Get Header DateTime Value {control.Name}"),
- driver => ExecuteInHeaderContainer(driver, xpathToContainer,
+ driver => ExecuteInHeaderContainer(driver, xpathToContainer,
container => TryGetValue(driver, container, control)));
}
@@ -4151,7 +4169,7 @@ internal BrowserCommandResult SelectDashboard(string dashboardName, int th
internal void EnablePerformanceCenter()
{
- Browser.Driver.Navigate().GoToUrl(string.Format("{0}&perf=true", Browser.Driver.Url));
+ Browser.Driver.Navigate().GoToUrl($"{Browser.Driver.Url}&perf=true");
Browser.Driver.WaitForPageToLoad();
Browser.Driver.WaitForTransaction();
}
@@ -4163,6 +4181,11 @@ internal void ThinkTime(int milliseconds)
Browser.ThinkTime(milliseconds);
}
+ internal void ThinkTime(TimeSpan timespan)
+ {
+ ThinkTime((int)timespan.TotalMilliseconds);
+ }
+
internal void Dispose()
{
Browser.Dispose();
diff --git a/Microsoft.Dynamics365.UIAutomation.Api.UCI/XrmApp.cs b/Microsoft.Dynamics365.UIAutomation.Api.UCI/XrmApp.cs
index 7dfd17fb..31192c13 100644
--- a/Microsoft.Dynamics365.UIAutomation.Api.UCI/XrmApp.cs
+++ b/Microsoft.Dynamics365.UIAutomation.Api.UCI/XrmApp.cs
@@ -43,6 +43,11 @@ public void ThinkTime(int milliseconds)
{
_client.ThinkTime(milliseconds);
}
+ public void ThinkTime(TimeSpan timespan)
+ {
+ _client.ThinkTime((int)timespan.TotalMilliseconds);
+ }
+
public void Dispose()
{
_client?.Dispose();
diff --git a/Microsoft.Dynamics365.UIAutomation.Browser/Extensions/SeleniumExtensions.cs b/Microsoft.Dynamics365.UIAutomation.Browser/Extensions/SeleniumExtensions.cs
index 27ea225b..448df279 100644
--- a/Microsoft.Dynamics365.UIAutomation.Browser/Extensions/SeleniumExtensions.cs
+++ b/Microsoft.Dynamics365.UIAutomation.Browser/Extensions/SeleniumExtensions.cs
@@ -7,6 +7,7 @@
using OpenQA.Selenium.Support.Events;
using OpenQA.Selenium.Support.UI;
using System;
+using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
diff --git a/Microsoft.Dynamics365.UIAutomation.Browser/Extensions/TimeExtensions.cs b/Microsoft.Dynamics365.UIAutomation.Browser/Extensions/TimeExtensions.cs
new file mode 100644
index 00000000..78fdafd0
--- /dev/null
+++ b/Microsoft.Dynamics365.UIAutomation.Browser/Extensions/TimeExtensions.cs
@@ -0,0 +1,13 @@
+// Created by: Rodriguez Mustelier Angel (rodang)
+// Modify On: 2020-02-09 14:05
+
+using System;
+
+namespace Microsoft.Dynamics365.UIAutomation.Browser
+{
+ public static class TimeExtensions
+ {
+ public static TimeSpan Seconds(this int value)
+ => TimeSpan.FromSeconds(value);
+ }
+}
\ No newline at end of file
diff --git a/Microsoft.Dynamics365.UIAutomation.Browser/Microsoft.Dynamics365.UIAutomation.Browser.csproj b/Microsoft.Dynamics365.UIAutomation.Browser/Microsoft.Dynamics365.UIAutomation.Browser.csproj
index ee96443d..e8422a04 100644
--- a/Microsoft.Dynamics365.UIAutomation.Browser/Microsoft.Dynamics365.UIAutomation.Browser.csproj
+++ b/Microsoft.Dynamics365.UIAutomation.Browser/Microsoft.Dynamics365.UIAutomation.Browser.csproj
@@ -80,6 +80,7 @@
+
diff --git a/Microsoft.Dynamics365.UIAutomation.Sample/UCI/CommandBar/AssignAccount.cs b/Microsoft.Dynamics365.UIAutomation.Sample/UCI/CommandBar/AssignAccount.cs
index ed719eaf..ccd325a2 100644
--- a/Microsoft.Dynamics365.UIAutomation.Sample/UCI/CommandBar/AssignAccount.cs
+++ b/Microsoft.Dynamics365.UIAutomation.Sample/UCI/CommandBar/AssignAccount.cs
@@ -3,6 +3,7 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Dynamics365.UIAutomation.Api.UCI;
+using Microsoft.Dynamics365.UIAutomation.Browser;
namespace Microsoft.Dynamics365.UIAutomation.Sample.UCI
@@ -25,9 +26,22 @@ public void UCITestAssignAccount()
_xrmApp.ThinkTime(2000);
+ string name = _xrmApp.Entity.GetHeaderValue(new LookupItem{ Name = "ownerid" });
+ Assert.IsNotNull(name);
+
_xrmApp.CommandBar.ClickCommand("Assign");
+ _xrmApp.Dialogs.Assign(Dialogs.AssignTo.User, name);
+ }
- _xrmApp.Dialogs.Assign(Dialogs.AssignTo.User, "Grant");
+ [TestMethod]
+ public void UCITestAssignAccount_ToMe()
+ {
+ _xrmApp.Grid.OpenRecord(0);
+
+ _xrmApp.ThinkTime(2000);
+
+ _xrmApp.CommandBar.ClickCommand("Assign");
+ _xrmApp.Dialogs.Assign(Dialogs.AssignTo.Me);
}
}
}
diff --git a/Microsoft.Dynamics365.UIAutomation.Sample/UCI/Login/Login.cs b/Microsoft.Dynamics365.UIAutomation.Sample/UCI/Login/Login.cs
index 212e42b3..514919b8 100644
--- a/Microsoft.Dynamics365.UIAutomation.Sample/UCI/Login/Login.cs
+++ b/Microsoft.Dynamics365.UIAutomation.Sample/UCI/Login/Login.cs
@@ -20,7 +20,7 @@ public void MultiFactorLogin()
_xrmApp.CommandBar.ClickCommand("New");
- _xrmApp.Entity.SetValue("name", _timed("Test API Account"));
+ _xrmApp.Entity.SetValue("name", "Test API Account");
_xrmApp.Entity.SetValue("telephone1", "555-555-5555");
}
}
diff --git a/Microsoft.Dynamics365.UIAutomation.Sample/UCI/TestsBase.cs b/Microsoft.Dynamics365.UIAutomation.Sample/UCI/TestsBase.cs
index 10a40bd5..8e731c0d 100644
--- a/Microsoft.Dynamics365.UIAutomation.Sample/UCI/TestsBase.cs
+++ b/Microsoft.Dynamics365.UIAutomation.Sample/UCI/TestsBase.cs
@@ -22,8 +22,16 @@ public class TestsBase
public virtual void InitTest()
{
- CreateApp();
- NavigateToHomePage();
+ try
+ {
+ CreateApp();
+ NavigateToHomePage();
+ }
+ catch
+ {
+ CloseApp();
+ throw;
+ }
}
public virtual void FinishTest()