Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public void CloseOpportunity(double revenue, DateTime closeDate, string descript
/// </summary>
/// <param name="to">Enum used to assign record to user or team</param>
/// <param name="userOrTeamName">Name of the user or team to assign to</param>
public void Assign(Dialogs.AssignTo to, string userOrTeamName = "")
public void Assign(AssignTo to, string userOrTeamName = null)
{
_client.AssignDialog(to, userOrTeamName);
}
Expand Down
122 changes: 58 additions & 64 deletions Microsoft.Dynamics365.UIAutomation.Api.UCI/WebClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -235,6 +236,7 @@ private void EnterOneTimeCode(IWebDriver driver, SecureString mfaSecrectKey)
if (attempts >= Constants.DefaultRetryAttempts)
throw;
}

attempts++;
ThinkTime(Constants.DefaultRetryDelay);
}
Expand Down Expand Up @@ -901,56 +903,47 @@ internal BrowserCommandResult<bool> ConfirmationDialog(bool ClickConfirmButton)
});
}

internal BrowserCommandResult<bool> AssignDialog(Dialogs.AssignTo to, string userOrTeamName)
internal BrowserCommandResult<bool> 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;
});
Expand Down Expand Up @@ -1311,27 +1304,26 @@ internal BrowserCommandResult<bool> SwitchView(string viewName, int thinkTime =
internal BrowserCommandResult<bool> 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<Actions, Actions> 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;
Expand Down Expand Up @@ -2223,13 +2215,15 @@ 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)
{
field.SendKeys(Keys.Control + "a");
field.SendKeys(Keys.Backspace);
}

ThinkTime(500);
}

Expand Down Expand Up @@ -2637,7 +2631,7 @@ internal BrowserCommandResult<MultiValueOptionSet> 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));
Expand Down Expand Up @@ -2909,7 +2903,7 @@ internal BrowserCommandResult<bool> 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)));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System;
using System.Drawing;
using OpenQA.Selenium;

namespace Microsoft.Dynamics365.UIAutomation.Browser
{
public static class RelativePositions
{
public static Func<Point> 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<Point> 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<Point> 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<Point> 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);
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
{
Expand All @@ -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<Point> 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<Point> offsetFunc = null, bool ignoreStaleElementException = true)
=> driver.Perform(a => a.DoubleClick(), element, offsetFunc, ignoreStaleElementException);

public static void Perform(this IWebDriver driver, Func<Actions, Actions> action, IWebElement element, Func<Point> 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)
{
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,10 @@
<Compile Include="DynamicJsonConverter.cs" />
<Compile Include="Element.cs" />
<Compile Include="Extensions\DictionaryExtensions.cs" />
<Compile Include="Extensions\RelativePositions.cs" />
<Compile Include="Extensions\SeleniumExtensions.cs" />
<Compile Include="Extensions\StringExtensions.cs" />
<Compile Include="Extensions\TimeExtensions.cs" />
<Compile Include="ICommandResult.cs" />
<Compile Include="InteractiveBrowser.cs" />
<Compile Include="NavigationOperation.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
}
}
}