Skip to content

Commit

Permalink
Working in UCI
Browse files Browse the repository at this point in the history
- Rebuild FormJS Class Structure
- Add Method xrmApp.Entity.IsTabVisible
- Change Default Command Options for More Time / Retries / not thows exection without retry
  • Loading branch information
AngelRodriguez8008 committed Oct 25, 2019
1 parent 9099219 commit aaa0470
Show file tree
Hide file tree
Showing 19 changed files with 266 additions and 134 deletions.
7 changes: 7 additions & 0 deletions Microsoft.Dynamics365.UIAutomation.Api.UCI/Elements/Entity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,13 @@ public void SelectTab(string tabName, string subTabName = "")
_client.SelectTab(tabName, subTabName);
}

/// <summary>
/// Opens any tab on the web page.
/// </summary>
/// <param name="tabName">The name of the tab based on the References class</param>
public BrowserCommandResult<bool> IsTabVisible(string tabName) => _client.IsTabVisible(tabName);


public void SetHeaderValue(string field, string value)
{
_client.SetHeaderValue(field, value);
Expand Down
29 changes: 15 additions & 14 deletions Microsoft.Dynamics365.UIAutomation.Api.UCI/Elements/FormJS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,25 @@ namespace Microsoft.Dynamics365.UIAutomation.Api.UCI
{
public class FormJS : Element
{
private readonly FormJSPage _worker;
private readonly FormJSWorker _worker;
private readonly Pages.FormJS _page;

public FormJS(WebClient client)
{
_worker = new FormJSPage(client.Browser);
_worker = new FormJSWorker(client);
_page = new Pages.FormJS(_worker);
}

public BrowserCommandResult<TResult> ExecuteJS<T, TResult>(string commandName, string code, Func<T, TResult> converter) => _page.ExecuteJS(commandName, code, converter);
public bool ExecuteJS(string commandName, string code, params object[] args) => _page.ExecuteJS(commandName, code, args);
public BrowserCommandResult<T> ExecuteJS<T>(string commandName, string code) => _page.ExecuteJS<T>(commandName, code);

public BrowserCommandOptions GetOptions(string commandName) => _worker.GetOptions(commandName);
public bool SwitchToContent() => _worker.SwitchToContent();
public BrowserCommandResult<T> GetAttributeValue<T>(string attributte) => _worker.GetAttributeValue<T>(attributte);
public bool SetAttributeValue<T>(string attributte, T value) => _worker.SetAttributeValue(attributte, value);
public bool Clear(string attribute) => _worker.Clear(attribute);
public BrowserCommandResult<Guid> GetEntityId() => _worker.GetEntityId();
public BrowserCommandResult<bool> IsControlVisible(string attributte) => _worker.IsControlVisible(attributte);
public BrowserCommandResult<bool> IsDirty(string attributte) => _worker.IsDirty(attributte);
public BrowserCommandResult<FormJSPage.RequiredLevel> GetRequiredLevel(string attributte) => _worker.GetRequiredLevel(attributte);
public BrowserCommandResult<T> ExecuteJS<T>(string commandName, string code) => _worker.ExecuteJS<T>(commandName, code);
public BrowserCommandResult<TResult> ExecuteJS<T, TResult>(string commandName, string code, Func<T, TResult> converter) => _worker.ExecuteJS(commandName, code, converter);
public bool ExecuteJS(string commandName, string code, params object[] args) => _worker.ExecuteJS(commandName, code, args);
public BrowserCommandResult<T> GetAttributeValue<T>(string attributte) => _page.GetAttributeValue<T>(attributte);
public bool SetAttributeValue<T>(string attributte, T value) => _page.SetAttributeValue(attributte, value);
public bool Clear(string attribute) => _page.Clear(attribute);
public BrowserCommandResult<Guid> GetEntityId() => _page.GetEntityId();
public BrowserCommandResult<bool> IsControlVisible(string attributte) => _page.IsControlVisible(attributte);
public BrowserCommandResult<bool> IsDirty(string attributte) => _page.IsDirty(attributte);
public BrowserCommandResult<FormJSPage.RequiredLevel> GetRequiredLevel(string attributte) => _page.GetRequiredLevel(attributte);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Created by: Rodriguez Mustelier Angel --
// Modify On: 2019-10-21 04:20

using System;
using Microsoft.Dynamics365.UIAutomation.Api.Pages;
using Microsoft.Dynamics365.UIAutomation.Browser;
using OpenQA.Selenium.Support.Extensions;

namespace Microsoft.Dynamics365.UIAutomation.Api.UCI
{
public class FormJSWorker : Element, IFormJSWorker
{
private readonly Pages.FormJSWorker _worker;

public FormJSWorker(WebClient client)
{
_worker = new Pages.FormJSWorker(client.Browser);
}

public BrowserCommandResult<TResult> ExecuteJS<T, TResult>(string commandName, string code, Func<T, TResult> converter)
{
if (converter == null)
throw new ArgumentNullException(nameof(converter));

return _worker.Execute(_worker.GetOptions(commandName), driver =>
{
driver.WaitForPageToLoad();

T result = driver.ExecuteJavaScript<T>(code);
return converter(result);
});
}

public bool ExecuteJS(string commandName, string code, params object[] args)
{
return _worker.Execute(_worker.GetOptions(commandName), driver =>
{
driver.WaitForPageToLoad();

driver.ExecuteJavaScript(code, args);
return true;
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ public static class EntityExtensions
public static BrowserCommandResult<string> GetLookupValue(this Entity entity, string attribute) =>
entity.GetValue(new LookupItem {Name = attribute});

public static void SetLookupValue(this Entity entity, string attribute, string value)
{
entity.SetValue(attribute, value);
entity.SelectLookup(new LookupItem{ Name = attribute, Index = 0});
}

public static void SetLookupValue(this Entity entity, string attribute, string value) =>
entity.SetValue(new LookupItem { Name = attribute, Value = value });

public static void ClearLookup(this Entity entity, string attribute) =>
entity.RemoveValues(new []{new LookupItem{ Name = attribute }});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
<Compile Include="Elements\Dialog.cs" />
<Compile Include="Elements\Entity.cs" />
<Compile Include="Elements\FormJS.cs" />
<Compile Include="Elements\FormJSWorker.cs" />
<Compile Include="Elements\GlobalSearch.cs" />
<Compile Include="Elements\Lookup.cs" />
<Compile Include="Elements\Grid.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=elements/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
Original file line number Diff line number Diff line change
Expand Up @@ -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.1411")]
[assembly: AssemblyFileVersion("1.0.19282.1411")]
[assembly: AssemblyVersion("1.0.19295.1032")]
[assembly: AssemblyFileVersion("1.0.19295.1032")]
67 changes: 57 additions & 10 deletions Microsoft.Dynamics365.UIAutomation.Api.UCI/WebClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using OpenQA.Selenium.Support.UI;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Security;
using System.Threading;
Expand All @@ -28,10 +27,10 @@ internal BrowserCommandOptions GetOptions(string commandName)
{
return new BrowserCommandOptions(Constants.DefaultTraceSource,
commandName,
0,
0,
Constants.DefaultRetryAttempts,
Constants.DefaultRetryDelay,
null,
true,
false,
typeof(NoSuchElementException), typeof(StaleElementReferenceException));
}

Expand Down Expand Up @@ -1798,7 +1797,7 @@ internal BrowserCommandResult<bool> SetValue(LookupItem control, int index = 0)
{
return this.Execute(GetOptions($"Set Lookup Value: {control.Name}"), driver =>
{
driver.WaitForTransaction(5);
driver.WaitForTransaction(120);

var fieldContainer = driver.WaitUntilAvailable(By.XPath(AppElements.Xpath[AppReference.Entity.TextFieldLookupFieldContainer].Replace("[NAME]", control.Name)));

Expand All @@ -1814,11 +1813,14 @@ internal BrowserCommandResult<bool> SetValue(LookupItem control, int index = 0)
input.SendKeys(Keys.Backspace);
input.SendKeys(control.Value, true);

driver.ClickWhenAvailable(By.XPath(AppElements.Xpath[AppReference.Entity.TextFieldLookupSearchButton].Replace("[NAME]", control.Name)));
var byXPath = By.XPath(AppElements.Xpath[AppReference.Entity.TextFieldLookupSearchButton].Replace("[NAME]", control.Name));
driver.WaitUntilVisible(byXPath);

driver.ClickWhenAvailable(byXPath);
driver.WaitForTransaction();
}

if (control.Value != null && control.Value != "")
if (!string.IsNullOrEmpty(control.Value))
{
SetLookUpByValue(driver, control, index);
}
Expand Down Expand Up @@ -3317,16 +3319,61 @@ internal void ClickTab(IWebElement tabList, string xpath, string name)
searchScope = Browser.Driver.FindElement(By.XPath(AppElements.Xpath[AppReference.Entity.MoreTabsMenu]));
}


if (searchScope.TryFindElement(By.XPath(string.Format(xpath, name)), out IWebElement listItem))
if (searchScope != null && searchScope.TryFindElement(By.XPath(string.Format(xpath, name)), out IWebElement listItem))
{
listItem.Click(true);
}
else
{
throw new Exception($"The tab with name: {name} does not exist");
}

}

/// <returns>True on success, Exception on failure to invoke any action</returns>
internal BrowserCommandResult<bool> IsTabVisible(string tabName, string subTabName = "", int thinkTime = Constants.DefaultThinkTime)
{
Browser.ThinkTime(thinkTime);

return Execute("Is Tab Visible", driver =>
{
IWebElement tabList = driver.WaitUntilAvailable(By.XPath(AppElements.Xpath[AppReference.Entity.TabList]));
if (tabList == null)
return false;

bool result;
//Click Sub Tab if provided
if (string.IsNullOrEmpty(subTabName))
{
result = IsTabVisible(tabList, AppElements.Xpath[AppReference.Entity.Tab], tabName);
}
else
{
ClickTab(tabList, AppElements.Xpath[AppReference.Entity.Tab], tabName);
result = IsTabVisible(tabList, AppElements.Xpath[AppReference.Entity.SubTab], subTabName);
}
return result;
});
}


internal bool IsTabVisible(IWebElement tabList, string xpath, string name)
{
// Look for the tab in the tab list, else in the more tabs menu
IWebElement searchScope = null;
if(tabList.HasElement(By.XPath(string.Format(xpath, name))))
{
searchScope = tabList;

}
else if(tabList.TryFindElement(By.XPath(AppElements.Xpath[AppReference.Entity.MoreTabs]), out IWebElement moreTabsButton))
{
moreTabsButton.Click();
searchScope = Browser.Driver.FindElement(By.XPath(AppElements.Xpath[AppReference.Entity.MoreTabsMenu]));
}

IWebElement listItem = null;
var result = searchScope != null && searchScope.TryFindElement(By.XPath(string.Format(xpath, name)), out listItem);
return result && listItem != null;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@
<Compile Include="LoginRedirectEventArgs.cs" />
<Compile Include="Office365Browser.cs" />
<Compile Include="Pages\FormJS.cs" />
<Compile Include="Pages\FormJSWorker.cs" />
<Compile Include="Pages\IFormJSWorker.cs" />
<Compile Include="Pages\Office365.cs" />
<Compile Include="Pages\WindowPerformanceNavigation.cs" />
<Compile Include="Pages\Administration.cs" />
Expand Down
23 changes: 21 additions & 2 deletions Microsoft.Dynamics365.UIAutomation.Api/Pages/Entity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,7 @@ public BrowserCommandResult<bool> CollapseTab(string name, int thinkTime = Const

return this.Execute(GetOptions($"Collapse Tab: {name}"), driver =>
{
if (!driver.HasElement(By.XPath(Elements.Xpath[Reference.Entity.Tab].Replace("[NAME]", name))))
if (!IsTabVisible(driver, name))
{
throw new InvalidOperationException($"Tab with name '{name}' does not exist.");
}
Expand Down Expand Up @@ -720,6 +720,19 @@ public BrowserCommandResult<bool> DismissAlertIfPresent(bool stay = false)
});
}

/// <summary>
/// Expands the Tab on a CRM Entity form.
/// </summary>
/// <param name="name">The name of the Tab.</param>
/// <param name="thinkTime">Used to simulate a wait time between human interactions. The Default is 2 seconds.</param>
/// <example>xrmBrowser.Entity.ExpandTab("Summary");</example>
public BrowserCommandResult<bool> IsTabVisible(string name, int thinkTime = Constants.DefaultThinkTime)
{
Browser.ThinkTime(thinkTime);

return Execute(GetOptions($"Is Tab Visible: {name}"), driver => IsTabVisible(driver, name));
}

/// <summary>
/// Expands the Tab on a CRM Entity form.
/// </summary>
Expand All @@ -732,7 +745,7 @@ public BrowserCommandResult<bool> ExpandTab(string name, int thinkTime = Constan

return this.Execute(GetOptions($"Expand Tab: {name}"), driver =>
{
if (!driver.HasElement(By.XPath(Elements.Xpath[Reference.Entity.Tab].Replace("[NAME]", name))))
if (IsTabVisible(driver, name))
{
throw new InvalidOperationException($"Tab with name '{name}' does not exist.");
}
Expand All @@ -745,6 +758,12 @@ public BrowserCommandResult<bool> ExpandTab(string name, int thinkTime = Constan
});
}


private static bool IsTabVisible(IWebDriver driver, string name)
{
return driver.HasElement(By.XPath(Elements.Xpath[Reference.Entity.Tab].Replace("[NAME]", name)));
}

/// <summary>
/// Gets the value of a Text/Description field on an Entity footer.
/// </summary>
Expand Down
Loading

0 comments on commit aaa0470

Please sign in to comment.