From 1a6ecfe443cb7ff9eb6c9ebf74a30a6dcdbe6ff6 Mon Sep 17 00:00:00 2001 From: "Angel A. Rodriguez" Date: Tue, 6 Jul 2021 16:03:48 +0200 Subject: [PATCH 1/3] if AppId already in URL, move faster --- .../Properties/AssemblyInfo.cs | 4 +- .../WebClient.cs | 61 ++++++++++--------- .../UCI/Login/Login.cs | 16 ++--- 3 files changed, 41 insertions(+), 40 deletions(-) diff --git a/Microsoft.Dynamics365.UIAutomation.Api.UCI/Properties/AssemblyInfo.cs b/Microsoft.Dynamics365.UIAutomation.Api.UCI/Properties/AssemblyInfo.cs index bde89d81..e1d5d542 100644 --- a/Microsoft.Dynamics365.UIAutomation.Api.UCI/Properties/AssemblyInfo.cs +++ b/Microsoft.Dynamics365.UIAutomation.Api.UCI/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.19282.1210")] -[assembly: AssemblyFileVersion("1.0.19282.1210")] +[assembly: AssemblyVersion("1.0.21187.1348")] +[assembly: AssemblyFileVersion("1.0.21187.1348")] diff --git a/Microsoft.Dynamics365.UIAutomation.Api.UCI/WebClient.cs b/Microsoft.Dynamics365.UIAutomation.Api.UCI/WebClient.cs index bbc55757..496cce72 100644 --- a/Microsoft.Dynamics365.UIAutomation.Api.UCI/WebClient.cs +++ b/Microsoft.Dynamics365.UIAutomation.Api.UCI/WebClient.cs @@ -49,26 +49,39 @@ internal BrowserCommandResult InitializeModes() // Wait for main page to load before attempting this. If you don't do this it might still be authenticating and the URL will be wrong WaitForMainPage(); - var uri = driver.Url; + string uri = driver.Url; + if (string.IsNullOrEmpty(uri)) + return false; + + var prevQuery = GetUrlQueryParams(uri); var queryParams = "&flags=easyreproautomation=true"; - if (Browser.Options.UCITestMode) queryParams += ",testmode=true"; - if (Browser.Options.UCIPerformanceMode) queryParams += "&perf=true"; - - if (!uri.Contains(queryParams) && !uri.Contains(HttpUtility.UrlEncode(queryParams))) - { - var testModeUri = uri + queryParams; + var options = Browser.Options; + if (options.UCITestMode) queryParams += ",testmode=true"; + if (options.UCIPerformanceMode) queryParams += "&perf=true"; - driver.Navigate().GoToUrl(testModeUri); - } + if (prevQuery.Contains(queryParams)) + return true; + + var testModeUri = uri + queryParams; + driver.Navigate().GoToUrl(testModeUri); // Again wait for loading WaitForMainPage(); - return true; }); } + private static string GetUrlQueryParams(string uri) + { + if (string.IsNullOrEmpty(uri)) + return string.Empty; + + var decoded = HttpUtility.UrlDecode(uri); + var result = new Uri(decoded).Query.ToLower(); + return result; + } + public string[] OnlineDomains { get; set; } @@ -283,7 +296,7 @@ internal BrowserCommandResult PassThroughLogin(Uri uri) //else we landed on the Web Client main page or app picker page SwitchToDefaultContent(driver); }, - () => new InvalidOperationException("Load Main Page Fail.") + () => throw new InvalidOperationException("Load Main Page Fail.") ); return LoginResult.Success; @@ -364,28 +377,16 @@ internal BrowserCommandResult OpenApp(string appName, int thinkTime = Cons { driver.WaitForPageToLoad(); driver.SwitchTo().DefaultContent(); - var success = false; - //Handle left hand Nav in Web Client - if (!driver.Url.Contains("appid")) - { - success = TryToClickInAppTile(appName, driver); - } - - else if (driver.Url.Contains("forceUCI=1")) - { - success = TryOpenAppFromMenu(driver, appName, AppReference.Navigation.UCIAppMenuButton); - } - else - { - success = TryOpenAppFromMenu(driver, appName, AppReference.Navigation.WebAppMenuButton); - } + string url = GetUrlQueryParams(driver.Url); + var success = url.Contains("appid=") || url.Contains("app=") || // already in some app + TryToClickInAppTile(appName, driver) || + TryOpenAppFromMenu(driver, appName, AppReference.Navigation.UCIAppMenuButton) || + TryOpenAppFromMenu(driver, appName, AppReference.Navigation.WebAppMenuButton); //Handle left hand Nav in Web Client if (!success) throw new InvalidOperationException($"App Name {appName} not found."); - - Thread.Sleep(1000); - WaitForMainPage(); + InitializeModes(); // Wait for app page elements to be visible (shell and sitemapLauncherButton) @@ -397,7 +398,7 @@ internal BrowserCommandResult OpenApp(string appName, int thinkTime = Cons if (!success) throw new InvalidOperationException($"App '{appName}' was found but app page was not loaded."); - return success; + return true; }); } diff --git a/Microsoft.Dynamics365.UIAutomation.Sample/UCI/Login/Login.cs b/Microsoft.Dynamics365.UIAutomation.Sample/UCI/Login/Login.cs index 6901b3af..f4d92326 100644 --- a/Microsoft.Dynamics365.UIAutomation.Sample/UCI/Login/Login.cs +++ b/Microsoft.Dynamics365.UIAutomation.Sample/UCI/Login/Login.cs @@ -11,17 +11,17 @@ public class Login : TestsBase [TestCleanup] public override void FinishTest() => base.FinishTest(); - public override void NavigateToHomePage() => NavigateTo(UCIAppName.Sales, "Sales", "Accounts"); - [TestMethod] public void MultiFactorLogin() { - _xrmApp.Grid.SwitchView("All Accounts"); - - _xrmApp.CommandBar.ClickCommand("New"); + trace.Log("Login success"); + } - _xrmApp.Entity.SetValue("name", "Test API Account" + TestSettings.GetRandomString(5,5) ); - _xrmApp.Entity.SetValue("telephone1", "555-555-5555"); + [TestMethod] + public void MultiFactorLogin_NavigateToApp() + { + trace.Log("Login success"); + NavigateTo(UCIAppName.Sales, "Sales", "Accounts"); } - } + } } \ No newline at end of file From fa2da9ad3d1e96ab00ebbd7ec8c7de962b9488dd Mon Sep 17 00:00:00 2001 From: "Angel A. Rodriguez" Date: Wed, 7 Jul 2021 03:32:28 +0200 Subject: [PATCH 2/3] Fix URL missmatchs --- .../Properties/AssemblyInfo.cs | 4 +- .../WebClient.cs | 57 ++++++++++++------- .../UCI/Login/Login.cs | 25 +++++++- 3 files changed, 62 insertions(+), 24 deletions(-) diff --git a/Microsoft.Dynamics365.UIAutomation.Api.UCI/Properties/AssemblyInfo.cs b/Microsoft.Dynamics365.UIAutomation.Api.UCI/Properties/AssemblyInfo.cs index e1d5d542..3eca1241 100644 --- a/Microsoft.Dynamics365.UIAutomation.Api.UCI/Properties/AssemblyInfo.cs +++ b/Microsoft.Dynamics365.UIAutomation.Api.UCI/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.21187.1348")] -[assembly: AssemblyFileVersion("1.0.21187.1348")] +[assembly: AssemblyVersion("1.0.21187.2141")] +[assembly: AssemblyFileVersion("1.0.21187.2141")] diff --git a/Microsoft.Dynamics365.UIAutomation.Api.UCI/WebClient.cs b/Microsoft.Dynamics365.UIAutomation.Api.UCI/WebClient.cs index 496cce72..b656e52d 100644 --- a/Microsoft.Dynamics365.UIAutomation.Api.UCI/WebClient.cs +++ b/Microsoft.Dynamics365.UIAutomation.Api.UCI/WebClient.cs @@ -9,8 +9,10 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Collections.Specialized; using System.Diagnostics; using System.Linq; +using System.Resources; using System.Security; using System.Threading; using System.Web; @@ -54,13 +56,23 @@ internal BrowserCommandResult InitializeModes() return false; var prevQuery = GetUrlQueryParams(uri); - var queryParams = "&flags=easyreproautomation=true"; + bool requiereRedirect = false; + string queryParams = ""; + if (prevQuery.Get("flags") == null) + { + queryParams+= "&flags=easyreproautomation=true"; + if (Browser.Options.UCITestMode) + queryParams += ",testmode=true"; + requiereRedirect = true; + } - var options = Browser.Options; - if (options.UCITestMode) queryParams += ",testmode=true"; - if (options.UCIPerformanceMode) queryParams += "&perf=true"; + if (Browser.Options.UCIPerformanceMode && prevQuery.Get("perf") == null) + { + queryParams += "&perf=true"; + requiereRedirect = true; + } - if (prevQuery.Contains(queryParams)) + if (!requiereRedirect) return true; var testModeUri = uri + queryParams; @@ -72,13 +84,14 @@ internal BrowserCommandResult InitializeModes() }); } - private static string GetUrlQueryParams(string uri) + private NameValueCollection GetUrlQueryParams(string url) { - if (string.IsNullOrEmpty(uri)) - return string.Empty; + if (string.IsNullOrEmpty(url)) + return null; - var decoded = HttpUtility.UrlDecode(uri); - var result = new Uri(decoded).Query.ToLower(); + Uri uri = new Uri(url); + var query = uri.Query.ToLower(); + NameValueCollection result = HttpUtility.ParseQueryString(query); return result; } @@ -192,7 +205,7 @@ private LoginResult Login(IWebDriver driver, Uri uri, SecureString username, Sec return success ? LoginResult.Success : LoginResult.Failure; } - private bool IsUserAlreadyLogged() => WaitForMainPage(10.Seconds()); + private bool IsUserAlreadyLogged() => WaitForMainPage(2.Seconds()); private static string GenerateOneTimeCode(SecureString mfaSecretKey) { @@ -257,7 +270,7 @@ private static IWebElement GetOtcInput(IWebDriver driver) private static bool ClickStaySignedIn(IWebDriver driver) { var xpath = By.XPath(Elements.Xpath[Reference.Login.StaySignedIn]); - var element = driver.ClickIfVisible(xpath, 5.Seconds()); + var element = driver.ClickIfVisible(xpath, 2.Seconds()); return element != null; } @@ -377,12 +390,16 @@ internal BrowserCommandResult OpenApp(string appName, int thinkTime = Cons { driver.WaitForPageToLoad(); driver.SwitchTo().DefaultContent(); - - string url = GetUrlQueryParams(driver.Url); - var success = url.Contains("appid=") || url.Contains("app=") || // already in some app - TryToClickInAppTile(appName, driver) || - TryOpenAppFromMenu(driver, appName, AppReference.Navigation.UCIAppMenuButton) || - TryOpenAppFromMenu(driver, appName, AppReference.Navigation.WebAppMenuButton); //Handle left hand Nav in Web Client + + var query = GetUrlQueryParams(driver.Url); + bool isSomeAppOpen = query.Get("appid") != null || query.Get("app") != null; + + bool success = false; + if (!isSomeAppOpen) + success = TryToClickInAppTile(appName, driver); + else + success = TryOpenAppFromMenu(driver, appName, AppReference.Navigation.UCIAppMenuButton) || + TryOpenAppFromMenu(driver, appName, AppReference.Navigation.WebAppMenuButton); if (!success) throw new InvalidOperationException($"App Name {appName} not found."); @@ -406,7 +423,7 @@ private bool TryOpenAppFromMenu(IWebDriver driver, string appName, string appMen { bool found = false; var xpathToAppMenu = By.XPath(AppElements.Xpath[appMenuButton]); - driver.WaitUntilClickable(xpathToAppMenu, TimeSpan.FromSeconds(5), + driver.WaitUntilClickable(xpathToAppMenu, 5.Seconds(), appMenu => { appMenu.Click(true); @@ -448,7 +465,7 @@ private static bool TryToClickInAppTile(string appName, IWebDriver driver) } return true; }, - TimeSpan.FromSeconds(30) + 5.Seconds() ); var xpathToAppContainer = By.XPath(AppElements.Xpath[AppReference.Navigation.UCIAppContainer]); diff --git a/Microsoft.Dynamics365.UIAutomation.Sample/UCI/Login/Login.cs b/Microsoft.Dynamics365.UIAutomation.Sample/UCI/Login/Login.cs index f4d92326..3e2353c8 100644 --- a/Microsoft.Dynamics365.UIAutomation.Sample/UCI/Login/Login.cs +++ b/Microsoft.Dynamics365.UIAutomation.Sample/UCI/Login/Login.cs @@ -21,7 +21,28 @@ public void MultiFactorLogin() public void MultiFactorLogin_NavigateToApp() { trace.Log("Login success"); - NavigateTo(UCIAppName.Sales, "Sales", "Accounts"); + NavigateTo(UCIAppName.Sales); } - } + + [TestMethod] + public void MultiFactorLogin_NavigateToApp_CustomerService() + { + trace.Log("Login success"); + + NavigateTo(UCIAppName.CustomerService); + trace.Log("Open Customer Service Success"); + } + + [TestMethod] + public void MultiFactorLogin_NavigateToApp_ChangeApp() + { + trace.Log("Login success"); + NavigateTo(UCIAppName.Sales); + + trace.Log("Open Sales Success"); + + NavigateTo(UCIAppName.CustomerService); + trace.Log("Open Customer Service Success"); + } + } } \ No newline at end of file From 61f85e69527100638783d56fa8d8471e8dcb0386 Mon Sep 17 00:00:00 2001 From: "Angel A. Rodriguez" Date: Tue, 27 Jul 2021 10:40:51 +0200 Subject: [PATCH 3/3] Fix Typo (require) --- .../Properties/AssemblyInfo.cs | 4 ++-- Microsoft.Dynamics365.UIAutomation.Api.UCI/WebClient.cs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Microsoft.Dynamics365.UIAutomation.Api.UCI/Properties/AssemblyInfo.cs b/Microsoft.Dynamics365.UIAutomation.Api.UCI/Properties/AssemblyInfo.cs index 64349920..daf3eb74 100644 --- a/Microsoft.Dynamics365.UIAutomation.Api.UCI/Properties/AssemblyInfo.cs +++ b/Microsoft.Dynamics365.UIAutomation.Api.UCI/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.21191.0750")] -[assembly: AssemblyFileVersion("1.0.21191.0750")] \ No newline at end of file +[assembly: AssemblyVersion("1.0.21208.0840")] +[assembly: AssemblyFileVersion("1.0.21208.0840")] diff --git a/Microsoft.Dynamics365.UIAutomation.Api.UCI/WebClient.cs b/Microsoft.Dynamics365.UIAutomation.Api.UCI/WebClient.cs index 3868ff55..718d3791 100644 --- a/Microsoft.Dynamics365.UIAutomation.Api.UCI/WebClient.cs +++ b/Microsoft.Dynamics365.UIAutomation.Api.UCI/WebClient.cs @@ -56,23 +56,23 @@ internal BrowserCommandResult InitializeModes() return false; var prevQuery = GetUrlQueryParams(uri); - bool requiereRedirect = false; + bool requireRedirect = false; string queryParams = ""; if (prevQuery.Get("flags") == null) { queryParams+= "&flags=easyreproautomation=true"; if (Browser.Options.UCITestMode) queryParams += ",testmode=true"; - requiereRedirect = true; + requireRedirect = true; } if (Browser.Options.UCIPerformanceMode && prevQuery.Get("perf") == null) { queryParams += "&perf=true"; - requiereRedirect = true; + requireRedirect = true; } - if (!requiereRedirect) + if (!requireRedirect) return true; var testModeUri = uri + queryParams;