diff --git a/Microsoft.Dynamics365.UIAutomation.Api.UCI/DTO/AppElementReference.cs b/Microsoft.Dynamics365.UIAutomation.Api.UCI/DTO/AppElementReference.cs index b7fcaf4b..f1edcc3c 100644 --- a/Microsoft.Dynamics365.UIAutomation.Api.UCI/DTO/AppElementReference.cs +++ b/Microsoft.Dynamics365.UIAutomation.Api.UCI/DTO/AppElementReference.cs @@ -17,7 +17,8 @@ public static class Navigation public static string AreaMenu = "Nav_AreaMenu"; public static string AreaMoreMenu = "Nav_AreaMoreMenu"; public static string SubAreaContainer = "Nav_SubAreaContainer"; - public static string AppMenuButton = "Nav_AppMenuButton"; + public static string WebAppMenuButton = "Nav_WebAppMenuButton"; + public static string UCAppMenuButton = "Nav_UCAppMenuButton"; public static string SiteMapLauncherButton = "Nav_SiteMapLauncherButton"; public static string SiteMapLauncherCloseButton = "Nav_SiteMapLauncherCloseButton"; public static string SiteMapAreaMoreButton = "Nav_SiteMapAreaMoreButton"; @@ -263,7 +264,8 @@ public static class AppElements { "Nav_AreaMenu" , "//*[@data-lp-id=\"sitemap-areabar-overflow-flyout\"]"}, { "Nav_AreaMoreMenu" , "//ul[@role=\"menubar\"]"}, { "Nav_SubAreaContainer" , "//*[@data-id=\"navbar-container\"]/div/ul"}, - { "Nav_AppMenuButton" , "//*[@id=\"TabArrowDivider\"]/a"}, + { "Nav_WebAppMenuButton" , "//*[@id=\"TabArrowDivider\"]/a"}, + { "Nav_UCAppMenuButton" , "//button[@data-id=\"navbar-switch-app\"]"}, { "Nav_SiteMapLauncherButton", "//button[@data-lp-id=\"sitemap-launcher\"]" }, { "Nav_SiteMapLauncherCloseButton", "//button[@aria-label=\"Close Site Map\"]" }, { "Nav_SiteMapAreaMoreButton", "//button[@data-lp-id=\"sitemap-areaBar-more-btn\"]" }, diff --git a/Microsoft.Dynamics365.UIAutomation.Api.UCI/DTO/ElementReference.cs b/Microsoft.Dynamics365.UIAutomation.Api.UCI/DTO/ElementReference.cs index 446bff66..2eec6e8e 100644 --- a/Microsoft.Dynamics365.UIAutomation.Api.UCI/DTO/ElementReference.cs +++ b/Microsoft.Dynamics365.UIAutomation.Api.UCI/DTO/ElementReference.cs @@ -182,6 +182,7 @@ public static class Elements { "Login_Password", "//input[@type='password']"}, { "Login_SignIn", "id(\"cred_sign_in_button\")"}, { "Login_CrmMainPage", "//*[contains(@id,'crmTopBar')or contains(@data-id,'topBar')]"}, + { "Login_CrmUCMainPage", "//*[contains(@data-id,'topBar')]"}, { "Login_StaySignedIn", "//input[@id=\"idSIButton9\"]"}, //Notification @@ -723,6 +724,7 @@ public static class Login public static string LoginPassword = "Login_Password"; public static string SignIn = "Login_SignIn"; public static string CrmMainPage = "Login_CrmMainPage"; + public static string CrmUCMainPage = "Login_CrmUCMainPage"; public static string StaySignedIn = "Login_StaySignedIn"; } public static class Report diff --git a/Microsoft.Dynamics365.UIAutomation.Api.UCI/Elements/OnlineLogin.cs b/Microsoft.Dynamics365.UIAutomation.Api.UCI/Elements/OnlineLogin.cs index fe736071..079566b1 100644 --- a/Microsoft.Dynamics365.UIAutomation.Api.UCI/Elements/OnlineLogin.cs +++ b/Microsoft.Dynamics365.UIAutomation.Api.UCI/Elements/OnlineLogin.cs @@ -23,7 +23,7 @@ public void Login(Uri orgUrl) { _client.Login(orgUrl); - _client.InitializeModes(true); + _client.InitializeModes(); } /// @@ -36,7 +36,7 @@ public void Login(Uri orgUrl, SecureString username, SecureString password) { _client.Login(orgUrl, username, password); - _client.InitializeModes(true); + _client.InitializeModes(); } /// @@ -50,7 +50,7 @@ public void Login(Uri orgUrl, SecureString username, SecureString password, Acti { _client.Login(orgUrl, username, password, redirectAction); - _client.InitializeModes(true); + _client.InitializeModes(); } } diff --git a/Microsoft.Dynamics365.UIAutomation.Api.UCI/WebClient.cs b/Microsoft.Dynamics365.UIAutomation.Api.UCI/WebClient.cs index d65285ef..be870fd4 100644 --- a/Microsoft.Dynamics365.UIAutomation.Api.UCI/WebClient.cs +++ b/Microsoft.Dynamics365.UIAutomation.Api.UCI/WebClient.cs @@ -38,30 +38,26 @@ internal BrowserCommandOptions GetOptions(string commandName) typeof(NoSuchElementException), typeof(StaleElementReferenceException)); } - internal BrowserCommandResult InitializeModes(bool onlineLoginPath = false) + internal BrowserCommandResult InitializeModes() { return this.Execute(GetOptions("Initialize Unified Interface Modes"), driver => { var uri = driver.Url; - var queryParams = ""; + var queryParams = "&flags=easyreproautomation=true"; - if (Browser.Options.UCITestMode) queryParams += "&flags=testmode=true,easyreproautomation=true"; + if (Browser.Options.UCITestMode) queryParams += ",testmode=true"; if (Browser.Options.UCIPerformanceMode) queryParams += "&perf=true"; - if (!string.IsNullOrEmpty(queryParams) && !uri.Contains(queryParams)) + if(!uri.Contains(queryParams) && !uri.Contains(System.Web.HttpUtility.UrlEncode(queryParams))) { var testModeUri = uri + queryParams; driver.Navigate().GoToUrl(testModeUri); - - driver.WaitForPageToLoad(); - - if (!onlineLoginPath) - { - driver.WaitForTransaction(); - } + } + WaitForMainPage(); + return true; }); } @@ -69,6 +65,44 @@ internal BrowserCommandResult InitializeModes(bool onlineLoginPath = false public string[] OnlineDomains { get; set; } + #region PageWaits + internal void WaitForLoginPage() + { + IWebDriver driver = this.Browser.Driver; + + driver.WaitUntilVisible(By.XPath(Elements.Xpath[Reference.Login.CrmMainPage]) + , new TimeSpan(0, 0, 60), + e => { + + //determine if we landed on the Unified Client Main page + if (driver.HasElement(By.XPath(Elements.Xpath[Reference.Login.CrmUCMainPage]))) + { + e.WaitForPageToLoad(); + e.WaitForTransaction(); + } + else //else we landed on the Web Client main page or app picker page + { + e.WaitForPageToLoad(); + e.SwitchTo().Frame(0); + e.WaitForPageToLoad(); + //Switch Back to Default Content for Navigation Steps + e.SwitchTo().DefaultContent(); + } + }, + f => { throw new Exception("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.CrmUCMainPage]))) + { + driver.WaitForTransaction(); + } + } + #endregion + #region Login internal BrowserCommandResult Login(Uri uri) { @@ -141,17 +175,7 @@ private LoginResult Login(IWebDriver driver, Uri uri, SecureString username, Sec driver.ClickWhenAvailable(By.XPath(Elements.Xpath[Reference.Login.StaySignedIn])); } - driver.WaitUntilVisible(By.XPath(Elements.Xpath[Reference.Login.CrmMainPage]) - , new TimeSpan(0, 0, 60), - e => { - e.WaitForPageToLoad(); - e.SwitchTo().Frame(0); - e.WaitForPageToLoad(); - - //Switch Back to Default Content for Navigation Steps - e.SwitchTo().DefaultContent(); - }, - f => { throw new Exception("Login page failed."); }); + WaitForLoginPage(); } } @@ -163,21 +187,13 @@ internal BrowserCommandResult PassThroughLogin(Uri uri) { driver.Navigate().GoToUrl(uri); - driver.WaitUntilVisible(By.XPath(Elements.Xpath[Reference.Login.CrmMainPage]) - , new TimeSpan(0, 0, 60), - e => { - e.WaitForPageToLoad(); - e.SwitchTo().Frame(0); - e.WaitForPageToLoad(); - - //Switch Back to Default Content for Navigation Steps - e.SwitchTo().DefaultContent(); - }, - f => { throw new Exception("Login page failed."); }); + WaitForLoginPage(); return LoginResult.Success; }); } + + public void ADFSLoginAction(LoginRedirectEventArgs args) { @@ -254,34 +270,25 @@ internal BrowserCommandResult OpenApp(string appName, int thinkTime = Cons { driver.SwitchTo().DefaultContent(); - //Handle left hand Nav - if (driver.HasElement(By.XPath(AppElements.Xpath[AppReference.Navigation.AppMenuButton]))) + //Handle left hand Nav in Web Client + if (driver.HasElement(By.XPath(AppElements.Xpath[AppReference.Navigation.WebAppMenuButton]))) { - driver.ClickWhenAvailable(By.XPath(AppElements.Xpath[AppReference.Navigation.AppMenuButton])); - - 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); + driver.ClickWhenAvailable(By.XPath(AppElements.Xpath[AppReference.Navigation.WebAppMenuButton])); - if (button != null) - button.Click(true); - else - throw new InvalidOperationException($"App Name {appName} not found."); - - driver.WaitUntilVisible(By.XPath(AppElements.Xpath[AppReference.Application.Shell])); - driver.WaitUntilVisible(By.XPath(AppElements.Xpath[AppReference.Navigation.SiteMapLauncherButton])); - driver.WaitForPageToLoad(); + OpenAppFromMenu(driver, appName); + } + else if (driver.HasElement(By.XPath(AppElements.Xpath[AppReference.Navigation.UCAppMenuButton]))) //Handle Left Hand Nav in UC Client + { + driver.ClickWhenAvailable(By.XPath(AppElements.Xpath[AppReference.Navigation.UCAppMenuButton])); - driver.WaitForTransaction(); + OpenAppFromMenu(driver, appName); } else if (driver.HasElement(By.XPath(AppElements.Xpath[AppReference.Navigation.UCIAppContainer]))) //Handle main.aspx?ForcUCI=1 { var tileContainer = driver.FindElement(By.XPath(AppElements.Xpath[AppReference.Navigation.UCIAppContainer])); tileContainer.FindElement(By.XPath(AppElements.Xpath[AppReference.Navigation.UCIAppTile].Replace("[NAME]", appName))).Click(true); - driver.WaitForTransaction(); + WaitForMainPage(); } else { @@ -293,11 +300,12 @@ internal BrowserCommandResult OpenApp(string appName, int thinkTime = Cons var tileContainer = driver.FindElement(By.XPath(AppElements.Xpath[AppReference.Navigation.UCIAppContainer])); tileContainer.FindElement(By.XPath(AppElements.Xpath[AppReference.Navigation.UCIAppTile].Replace("[NAME]", appName))).Click(true); - driver.WaitForTransaction(); + WaitForMainPage(); } else throw new InvalidOperationException($"App Name {appName} not found."); } + Thread.Sleep(1000); InitializeModes(); @@ -305,6 +313,24 @@ internal BrowserCommandResult OpenApp(string appName, int thinkTime = Cons }); } + 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."); + + driver.WaitUntilVisible(By.XPath(AppElements.Xpath[AppReference.Application.Shell])); + driver.WaitUntilVisible(By.XPath(AppElements.Xpath[AppReference.Navigation.SiteMapLauncherButton])); + + WaitForMainPage(); + } internal BrowserCommandResult OpenGroupSubArea(string group, string subarea, int thinkTime = Constants.DefaultThinkTime) { this.Browser.ThinkTime(thinkTime); diff --git a/Microsoft.Dynamics365.UIAutomation.Sample/UCI/Read/OpenAccount.cs b/Microsoft.Dynamics365.UIAutomation.Sample/UCI/Read/OpenAccount.cs index c9ff47c7..8a205411 100644 --- a/Microsoft.Dynamics365.UIAutomation.Sample/UCI/Read/OpenAccount.cs +++ b/Microsoft.Dynamics365.UIAutomation.Sample/UCI/Read/OpenAccount.cs @@ -25,6 +25,10 @@ public void UCITestOpenActiveAccount() { xrmApp.OnlineLogin.Login(_xrmUri, _username, _password); + xrmApp.Navigation.OpenApp(UCIAppName.Sales); + xrmApp.Navigation.OpenApp("Sales"); + + xrmApp.Navigation.OpenApp(UCIAppName.Sales); xrmApp.Navigation.OpenApp(UCIAppName.Sales); xrmApp.Navigation.OpenSubArea("Sales", "Accounts");