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..98ba8473 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
@@ -235,6 +236,7 @@ private void EnterOneTimeCode(IWebDriver driver, SecureString mfaSecrectKey)
if (attempts >= Constants.DefaultRetryAttempts)
throw;
}
+
attempts++;
ThinkTime(Constants.DefaultRetryDelay);
}
@@ -901,56 +903,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]));
+ if (!inlineDialog)
+ return false;
- driver.WaitForTransaction();
+ //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");
- 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 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;
});
@@ -1311,27 +1304,26 @@ internal BrowserCommandResult SwitchView(string viewName, int thinkTime =
internal BrowserCommandResult OpenRecord(int index, int thinkTime = Constants.DefaultThinkTime, bool checkRecord = false)
{
ThinkTime(thinkTime);
-
return Execute(GetOptions("Open Grid Record"), driver =>
{
- IWebElement control = driver.WaitUntilAvailable(By.XPath(AppElements.Xpath[AppReference.Grid.Container]));
-
- var xpathToFind = checkRecord
- ? $"//div[@data-id='cell-{index}-1']"
- : $"//div[contains(@data-id, 'cell-{index}')]//a";
- control.ClickWhenAvailable(By.XPath(xpathToFind), "An error occur trying to open the record at position {index}");
-
- // Logic equivalent to fix #746 (by @rswafford)
- //var xpathToFind = $"//div[@data-id='cell-{index}-1']";
- //control.WaitUntilClickable(By.XPath(xpathToFind),
- // e =>
- // {
- // e.Click();
- // if (!checkRecord)
- // driver.DoubleClick(e);
- // },
- // $"An error occur trying to open the record at position {index}"
- // );
+ var xpathToGrid = By.XPath(AppElements.Xpath[AppReference.Grid.Container]);
+ IWebElement control = driver.WaitUntilAvailable(xpathToGrid);
+
+ Func action;
+ if (checkRecord)
+ action = e => e.Click();
+ else
+ action = e => e.DoubleClick();
+
+ var xpathToCell = By.XPath($".//div[@data-id='cell-{index}-1']");
+ control.WaitUntilClickable(xpathToCell,
+ cell =>
+ {
+ var emptyDiv = cell.FindElement(By.TagName("div"));
+ driver.Perform(action, cell, cell.LeftTo(emptyDiv));
+ },
+ $"An error occur trying to open the record at position {index}"
+ );
driver.WaitForTransaction();
return true;
@@ -2223,6 +2215,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 +2223,7 @@ private void ClearFieldValue(IWebElement field)
field.SendKeys(Keys.Control + "a");
field.SendKeys(Keys.Backspace);
}
+
ThinkTime(500);
}
@@ -2637,7 +2631,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 +2903,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)));
}
diff --git a/Microsoft.Dynamics365.UIAutomation.Browser/Extensions/RelativePositions.cs b/Microsoft.Dynamics365.UIAutomation.Browser/Extensions/RelativePositions.cs
new file mode 100644
index 00000000..0865300b
--- /dev/null
+++ b/Microsoft.Dynamics365.UIAutomation.Browser/Extensions/RelativePositions.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Drawing;
+using OpenQA.Selenium;
+
+namespace Microsoft.Dynamics365.UIAutomation.Browser
+{
+ public static class RelativePositions
+ {
+ public static Func Above(this IWebElement outer, IWebElement inner) =>
+ () =>
+ {
+ int x = outer.Size.Width / 2;
+ int y = (inner.Location.Y - outer.Location.Y) / 2;
+ return new Point(x, y);
+ };
+
+ public static Func Below(this IWebElement outer, IWebElement inner) =>
+ () =>
+ {
+ int x = outer.Size.Width / 2;
+ var outerEnd = outer.Location + outer.Size;
+ var innerEnd = inner.Location + inner.Size;
+ int dBelow = outerEnd.Y - innerEnd.Y;
+ int y = innerEnd.Y + dBelow / 2;
+ return new Point(x, y);
+ };
+
+ public static Func LeftTo(this IWebElement outer, IWebElement inner) =>
+ () =>
+ {
+ int x = (inner.Location.X - outer.Location.X) / 2;
+ int y = outer.Size.Height / 2;
+ return new Point(x, y);
+ };
+
+ public static Func RightTo(this IWebElement outer, IWebElement inner) =>
+ () =>
+ {
+ var outerEnd = outer.Location + outer.Size;
+ var innerEnd = inner.Location + inner.Size;
+ int dRight = outerEnd.X - innerEnd.X;
+ int x = innerEnd.X + dRight / 2;
+ int y = outer.Size.Height / 2;
+ return new Point(x, y);
+ };
+ }
+}
\ No newline at end of file
diff --git a/Microsoft.Dynamics365.UIAutomation.Browser/Extensions/SeleniumExtensions.cs b/Microsoft.Dynamics365.UIAutomation.Browser/Extensions/SeleniumExtensions.cs
index 27ea225b..198dad61 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;
@@ -59,7 +60,7 @@ public static void Hover(this IWebElement element, IWebDriver driver, bool ignor
try
{
Actions action = new Actions(driver);
- action.MoveToElement(element).Build().Perform();
+ action.MoveToElement(element).Perform();
}
catch (StaleElementReferenceException)
{
@@ -70,14 +71,27 @@ public static void Hover(this IWebElement element, IWebDriver driver, bool ignor
#endregion Click
+ public static void Click(this IWebDriver driver, IWebElement element, Func offsetFunc = null, bool ignoreStaleElementException = true)
+ => driver.Perform(a => a.Click(), element, offsetFunc, ignoreStaleElementException);
+
#region Double Click
- public static void DoubleClick(this IWebDriver driver, IWebElement element, bool ignoreStaleElementException = false)
+ public static void DoubleClick(this IWebDriver driver, IWebElement element, Func offsetFunc = null, bool ignoreStaleElementException = true)
+ => driver.Perform(a => a.DoubleClick(), element, offsetFunc, ignoreStaleElementException);
+
+ public static void Perform(this IWebDriver driver, Func action, IWebElement element, Func offsetFunc = null, bool ignoreStaleElementException = true)
{
try
{
- Actions actions = new Actions(driver);
- actions.DoubleClick(element).Build().Perform();
+ var actions = new Actions(driver);
+ if (offsetFunc == null)
+ actions = actions.MoveToElement(element);
+ else
+ {
+ var offset = offsetFunc();
+ actions = actions.MoveToElement(element, offset.X, offset.Y);
+ }
+ action(actions).Perform();
}
catch (StaleElementReferenceException)
{
@@ -86,12 +100,7 @@ public static void DoubleClick(this IWebDriver driver, IWebElement element, bool
}
}
- public static void DoubleClick(this IWebDriver driver, By by, bool ignoreStaleElementException = false)
- {
- var element = driver.FindElement(by);
- driver.DoubleClick(element, ignoreStaleElementException);
- }
-
+
#endregion
#region Script Execution
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..d601f616 100644
--- a/Microsoft.Dynamics365.UIAutomation.Browser/Microsoft.Dynamics365.UIAutomation.Browser.csproj
+++ b/Microsoft.Dynamics365.UIAutomation.Browser/Microsoft.Dynamics365.UIAutomation.Browser.csproj
@@ -78,8 +78,10 @@
+
+
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);
}
}
}